forked from Gitlink/microservices
Compare commits
253 Commits
master
...
dev_monito
| Author | SHA1 | Date |
|---|---|---|
|
|
4ada9fc829 | |
|
|
e8bdc8fc92 | |
|
|
3a0f0d84c5 | |
|
|
569eaa14ff | |
|
|
33e77ed05b | |
|
|
7c785d4743 | |
|
|
c890870e09 | |
|
|
07a70f12ce | |
|
|
5daaa3d54a | |
|
|
e87484b1e1 | |
|
|
c22addc4e5 | |
|
|
43d2ce4231 | |
|
|
fca7e4e502 | |
|
|
e92c412c4e | |
|
|
f94a885908 | |
|
|
5776ddd748 | |
|
|
661709efaf | |
|
|
7760f5afb3 | |
|
|
575170a801 | |
|
|
be80d64dd5 | |
|
|
6f1068f082 | |
|
|
3589a9b51a | |
|
|
e9e3852364 | |
|
|
1aabdcf752 | |
|
|
44f0bfb4c8 | |
|
|
ab58222217 | |
|
|
a3ccf62c10 | |
|
|
a4e92ca636 | |
|
|
8bfd8c6e1a | |
|
|
3e4c801cbd | |
|
|
c76b6efa20 | |
|
|
0d833872b6 | |
|
|
4782b8c0c0 | |
|
|
e792599fc3 | |
|
|
2e9c3d0f9d | |
|
|
b7e68454ac | |
|
|
e3921d833b | |
|
|
723825064c | |
|
|
02791388bd | |
|
|
5d14d5e56a | |
|
|
e3ddab5ceb | |
|
|
587a2707a7 | |
|
|
992c17b4c8 | |
|
|
0aa96e853a | |
|
|
34ab56eb8a | |
|
|
bdbd2da88d | |
|
|
30f8ce8184 | |
|
|
7fbfbdaf8d | |
|
|
93ed7838e6 | |
|
|
68988926b9 | |
|
|
5485d39894 | |
|
|
2516ba038e | |
|
|
e80d7f8a6f | |
|
|
bb9b4f05da | |
|
|
4bbf3c91e2 | |
|
|
00bde1ad9a | |
|
|
092d566de4 | |
|
|
27c5e64e1a | |
|
|
71f4e4bc8f | |
|
|
8c8e13a5e1 | |
|
|
82c74b9184 | |
|
|
290fc64c88 | |
|
|
b0aede3f93 | |
|
|
902f961469 | |
|
|
e904d854f6 | |
|
|
3dbdef7ab8 | |
|
|
072e85de82 | |
|
|
8f48c1030a | |
|
|
9380081443 | |
|
|
0646a3b773 | |
|
|
43e75440d5 | |
|
|
0ca345d200 | |
|
|
83c1457c50 | |
|
|
3f208de48a | |
|
|
bce79534bd | |
|
|
f402ec1748 | |
|
|
7de259d088 | |
|
|
1c9bc630d8 | |
|
|
c13748d494 | |
|
|
69e789d856 | |
|
|
02f215c2e4 | |
|
|
d1076e48d5 | |
|
|
b25411e35c | |
|
|
1f3d65fd39 | |
|
|
3f155f2270 | |
|
|
ee77bdb8a1 | |
|
|
631f6752a6 | |
|
|
39a8dde543 | |
|
|
0f0a639bf4 | |
|
|
cf2c5cffa3 | |
|
|
b89c235df3 | |
|
|
2d5d43b37e | |
|
|
32b58df5d1 | |
|
|
555ef0fc80 | |
|
|
46cbaccf64 | |
|
|
ebf1dc53cf | |
|
|
e6dadf2ccd | |
|
|
71cf4fb6fc | |
|
|
eed4b9d9eb | |
|
|
cad9ea1247 | |
|
|
02e369849d | |
|
|
f7e9d9350e | |
|
|
356b85fd35 | |
|
|
19a32e2f7c | |
|
|
b2f9921664 | |
|
|
2567386baa | |
|
|
8e10fee65f | |
|
|
310b423ec9 | |
|
|
705823ec3f | |
|
|
172e0ee92e | |
|
|
726ece8af9 | |
|
|
82f180d31c | |
|
|
e91ee14d63 | |
|
|
10a1b3f5cf | |
|
|
7f22a2c6ec | |
|
|
9c76980bdc | |
|
|
a861d69061 | |
|
|
53274c3b0e | |
|
|
32ded69b77 | |
|
|
36e9d84dd8 | |
|
|
4e0d281bf7 | |
|
|
fbcbe63ad4 | |
|
|
48e0510bb3 | |
|
|
3726e4b294 | |
|
|
335d05d2c3 | |
|
|
fa4ee4526b | |
|
|
405b2e07c1 | |
|
|
c6fd9a1c9d | |
|
|
bfbaa3491d | |
|
|
c97b64f3bc | |
|
|
83c8d5fe3e | |
|
|
7cff154598 | |
|
|
d0fcf1fbce | |
|
|
3cf7ced976 | |
|
|
ddb1a06acc | |
|
|
0c94e636e1 | |
|
|
0f2d37babe | |
|
|
6e72d6f762 | |
|
|
d330e7a56d | |
|
|
29dbc84989 | |
|
|
f055d0f28e | |
|
|
20ce451a9a | |
|
|
629822dcb9 | |
|
|
e7ca96f280 | |
|
|
f9956c305e | |
|
|
d13b38e980 | |
|
|
45c84d17b6 | |
|
|
71ec75c3e5 | |
|
|
0d0b0072c3 | |
|
|
8f84d425c8 | |
|
|
1cb6c3e758 | |
|
|
17a911c54e | |
|
|
adc86b04c9 | |
|
|
cd19bd94cc | |
|
|
dc814cffff | |
|
|
92bfd2c7f2 | |
|
|
6a71629784 | |
|
|
1e016300c7 | |
|
|
fdf61667f7 | |
|
|
22f350510c | |
|
|
2566f119d3 | |
|
|
19718b6123 | |
|
|
3fa2daac28 | |
|
|
2d304cfae0 | |
|
|
1f2f48c120 | |
|
|
19e298b67a | |
|
|
f70681d783 | |
|
|
8abb5a38bd | |
|
|
9eb10143f7 | |
|
|
9865c8bad9 | |
|
|
bc92fb8419 | |
|
|
a25048faad | |
|
|
8c068c4b79 | |
|
|
735d7fd9e9 | |
|
|
705a9241b6 | |
|
|
03b7c170e4 | |
|
|
0c0f27810e | |
|
|
4fd5c1cc4d | |
|
|
65a5b5d081 | |
|
|
e97b972f31 | |
|
|
828901d322 | |
|
|
33185a1d0c | |
|
|
29b6b2bbae | |
|
|
2883029641 | |
|
|
5eed69522c | |
|
|
c5d99153b8 | |
|
|
6f4a10f1cb | |
|
|
c6f58972a6 | |
|
|
53795b1b88 | |
|
|
1f653894cd | |
|
|
5af3df62ee | |
|
|
fde9893840 | |
|
|
e44f63a4c6 | |
|
|
6d47364cca | |
|
|
128a107f8f | |
|
|
65aaa7df5b | |
|
|
b1da0ba006 | |
|
|
ad3625a823 | |
|
|
115a3cbe12 | |
|
|
c9d08ef3d5 | |
|
|
3f795fadb5 | |
|
|
672476ba53 | |
|
|
1f55a7835e | |
|
|
0b16dbf195 | |
|
|
8111f6db61 | |
|
|
ae073b68bc | |
|
|
14072b1dff | |
|
|
12eecde9c4 | |
|
|
66e1b9aca6 | |
|
|
93e56ed555 | |
|
|
13d5e7aa46 | |
|
|
dc9a537feb | |
|
|
3d5d6bfc6e | |
|
|
bac9eeda5f | |
|
|
18f89d1b8e | |
|
|
c3b5dcafba | |
|
|
a0aec9bf88 | |
|
|
a511f39a13 | |
|
|
75f828b76c | |
|
|
4b1042c25d | |
|
|
e9c41768e1 | |
|
|
15aa7016b9 | |
|
|
f96cee3f4a | |
|
|
055b26ee29 | |
|
|
368a45e8b2 | |
|
|
2c5f0518ca | |
|
|
06fbbf7208 | |
|
|
6613950ff8 | |
|
|
8184eb2401 | |
|
|
213aee5587 | |
|
|
274af358dd | |
|
|
58bf8326c5 | |
|
|
5e19e53b94 | |
|
|
2be36ca12e | |
|
|
ad405c912e | |
|
|
6ef1fafac8 | |
|
|
39d43e3d68 | |
|
|
1eefa65c32 | |
|
|
c6b4a1bd80 | |
|
|
21ba1ce6bd | |
|
|
dd870b3cd3 | |
|
|
417d440549 | |
|
|
67b2e9ce7c | |
|
|
32b83749e2 | |
|
|
010d5e5354 | |
|
|
94e0be0e71 | |
|
|
2845d19aae | |
|
|
97b1c9437c | |
|
|
b0f9e06e18 | |
|
|
f58af4b0b5 | |
|
|
78cbd4b0ee | |
|
|
fca8490bdd | |
|
|
616bf1229f |
|
|
@ -2,13 +2,13 @@ package com.microservices.system.api;
|
|||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||
import com.microservices.common.core.constant.TokenConstants;
|
||||
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
||||
import com.microservices.system.api.model.GraphqlQueryVo;
|
||||
import feign.Response;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
|
|
@ -28,6 +28,14 @@ public interface RemoteGatewayService {
|
|||
@PostMapping("/sentinel/auth/login")
|
||||
Response loginSentinel(@RequestParam("username") String username, @RequestParam("password") String password);
|
||||
|
||||
/**
|
||||
* 登录Rancher
|
||||
*
|
||||
* @return 响应
|
||||
*/
|
||||
@PostMapping("/rancher/v3-public/localProviders/local?action=login")
|
||||
Response loginRancher(@RequestBody JSONObject loginBody);
|
||||
|
||||
/**
|
||||
* 登录Nacos
|
||||
*
|
||||
|
|
@ -43,4 +51,45 @@ public interface RemoteGatewayService {
|
|||
*/
|
||||
@PostMapping("/portainer/api/auth")
|
||||
Response loginPortainer(@RequestBody JSONObject loginBody);
|
||||
|
||||
@GetMapping("/prometheus/api/v1/query")
|
||||
JSONObject getPrometheusQueryRes(@RequestParam("query") String query,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/prometheus/api/v1/query_range")
|
||||
JSONObject getPrometheusQueryRangeRes(@RequestParam("query") String query,
|
||||
@RequestParam("step") Long step,
|
||||
@RequestParam("start") Long start,
|
||||
@RequestParam("end") Long end,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@PostMapping("/skywalking/graphql")
|
||||
JSONObject executeSkywalkingGql(@RequestBody GraphqlQueryVo gqlBody);
|
||||
|
||||
@GetMapping("/sentinel/app/briefinfos.json")
|
||||
JSONObject getSentinelAppList(@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/nacos/v1/ns/catalog/services?pageNo=1&pageSize=999")
|
||||
JSONObject getNacosServiceList(@RequestParam("serviceNameParam") String serviceNameParam, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/nacos/v1/cs/configs?types=yaml&search=blur&group=&pageNo=1&pageSize=10")
|
||||
JSONObject getGatewayNacosConfigList(@RequestParam("dataId") String dataId, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/nacos/v1/cs/listener")
|
||||
JSONObject getNacosConfigList(@RequestParam("ip") String ip, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/nacos/v1/cs/configs")
|
||||
String getNacosConfigDetail(@RequestParam("dataId") String dataId, @RequestParam("group") String group, @RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@PostMapping(value = "/nacos/v1/cs/configs", consumes = {"application/x-www-form-urlencoded"})
|
||||
Response updateNacosConfig(Map<String, ?> formParams, @RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||
|
||||
@PostMapping("/es/{esIndex}/_search")
|
||||
JSONObject executeElasticsearchQuery(@PathVariable("esIndex") String esIndex, @RequestBody JSONObject esBody);
|
||||
|
||||
@PostMapping("/es/{esIndex}/_doc/{docId}/_update")
|
||||
JSONObject executeElasticsearchUpdate(@PathVariable("esIndex") String esIndex,@PathVariable("docId") String docId, @RequestBody JSONObject esBody);
|
||||
|
||||
@PostMapping("/gns/notification/gitlink")
|
||||
JSONObject sendNotification(@RequestBody JSONObject body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package com.microservices.system.api;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.constant.Constants;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.constant.ServiceNameConstants;
|
||||
import com.microservices.common.core.constant.TokenConstants;
|
||||
import com.microservices.system.api.factory.RemoteGatewayFallbackFactory;
|
||||
import com.microservices.system.api.factory.RemoteRancherFallbackFactory;
|
||||
import feign.Response;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 网关
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Component
|
||||
@FeignClient(contextId = "RemoteRancherService", value = ServiceNameConstants.GATEWAY_SERVICE, fallbackFactory = RemoteRancherFallbackFactory.class)
|
||||
public interface RemoteRancherService {
|
||||
@GetMapping("/rancher/v3/clusters/{cluster_id}/namespaces")
|
||||
Response getK8sNamespaceList(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.daemonsets?exclude=metadata.managedFields")
|
||||
Response getK8sDaemonsetsList(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.deployments?exclude=metadata.managedFields")
|
||||
Response getK8sDeployList(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/apps.statefulsets?exclude=metadata.managedFields")
|
||||
Response getK8sStatefulList(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/nodes?exclude=metadata.managedFields")
|
||||
Response getK8sClusterNodeList(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/{fullKind}/{namespace}/{applicationName}")
|
||||
Response getK8sApplicationDetail(@PathVariable("cluster_id") String cluster_id,
|
||||
@PathVariable("fullKind") String fullKind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/pods/{namespace}")
|
||||
Response getK8sPodListByNamespace(@PathVariable("cluster_id") String cluster_id,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/pods")
|
||||
Response getK8sPodList(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/services/{nginxApplicationId}")
|
||||
Response getK8sServiceByApplicationId(@PathVariable("cluster_id") String cluster_id,
|
||||
@PathVariable("nginxApplicationId") String nginxApplicationId,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@DeleteMapping("/rancher/v1/pods/{namespace}/{podName}")
|
||||
Response deletePod(@PathVariable("namespace") String namespace,
|
||||
@PathVariable("podName") String podName,
|
||||
@RequestBody JSONObject deletePodBody,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@PutMapping("/rancher/v1/{fullKind}/{namespace}/{applicationName}")
|
||||
Response updateK8sApplication(@PathVariable("fullKind") String fullKind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestBody JSONObject applicationDetail,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||
|
||||
@PostMapping(value = "/rancher/v1/{fullKind}", consumes = {Constants.YAML_CONTENT_TYPE})
|
||||
Response createK8sApplication(@PathVariable("fullKind") String fullName,
|
||||
@RequestBody String yamlContent,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||
|
||||
@PostMapping(value = "/rancher/v1/management.cattle.io.clusters/{cluster_id}?action=apply")
|
||||
Response applyK8sYaml(@PathVariable("cluster_id") String cluster_id,
|
||||
@RequestBody JSONObject yamlContent,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String userKey);
|
||||
|
||||
@GetMapping("/rancher/apis/apps/v1/namespaces/{namespace}/{kindName}/{applicationName}")
|
||||
Response getApplicationYamlFile(@PathVariable("kindName") String kindName,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@PutMapping(value = "/rancher/v1/{fullKind}/{namespace}/{applicationName}", consumes = {Constants.YAML_CONTENT_TYPE})
|
||||
Response editK8sApplication(@PathVariable("fullKind") String fullKind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestBody String yamlContent,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@DeleteMapping("/rancher/v1/{fullKind}/{namespace}/{applicationName}")
|
||||
Response deleteApplication(@PathVariable("fullKind") String fullKind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/v1/configmaps/{namespace}")
|
||||
Response getK8sConfigmapByNamespace(@PathVariable("namespace") String namespace,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/v1/secrets/{namespace}")
|
||||
Response getK8sSecretByNamespace(@PathVariable("namespace") String namespace,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
@GetMapping("/rancher/k8s/clusters/{cluster_id}/v1/services/{namespace}")
|
||||
Response getK8sServiceByNamespace(@PathVariable("cluster_id") String cluster_id,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
|
||||
|
||||
@DeleteMapping("/rancher/v1/services/{serviceId}")
|
||||
Response deleteK8sService(@PathVariable("serviceId") String serviceId,@RequestHeader(TokenConstants.AUTHENTICATION) String token);
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
package com.microservices.system.api.factory;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.system.api.RemoteGatewayService;
|
||||
import com.microservices.system.api.model.GraphqlQueryVo;
|
||||
import feign.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -25,7 +27,12 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
|||
return new RemoteGatewayService() {
|
||||
|
||||
@Override
|
||||
public Response loginSentinel(String password, String username) {
|
||||
public Response loginSentinel(String username, String password) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response loginRancher(JSONObject loginBody) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +43,66 @@ public class RemoteGatewayFallbackFactory implements FallbackFactory<RemoteGatew
|
|||
|
||||
@Override
|
||||
public Response loginPortainer(JSONObject loginBody) {
|
||||
System.out.println(throwable.getMessage());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getPrometheusQueryRes(String query, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getPrometheusQueryRangeRes(String query, Long step, Long start, Long end, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject executeSkywalkingGql(GraphqlQueryVo gqlBody) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getSentinelAppList(String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getNacosServiceList(String serviceNameParam, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getGatewayNacosConfigList(String dataId, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getNacosConfigList(String ip, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNacosConfigDetail(String dataId, String group, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response updateNacosConfig(Map<String, ?> formParams, String userKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject executeElasticsearchQuery(String esIndex, JSONObject esBody) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject executeElasticsearchUpdate(String esIndex, String docId, JSONObject esBody) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject sendNotification(JSONObject body) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -0,0 +1,133 @@
|
|||
package com.microservices.system.api.factory;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.system.api.RemoteGatewayService;
|
||||
import com.microservices.system.api.RemoteRancherService;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import feign.FeignException;
|
||||
import feign.Response;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.openfeign.FallbackFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 用户服务降级处理
|
||||
*
|
||||
* @author microservices
|
||||
*/
|
||||
@Component
|
||||
public class RemoteRancherFallbackFactory implements FallbackFactory<RemoteRancherService> {
|
||||
private static final Logger log = LoggerFactory.getLogger(RemoteRancherFallbackFactory.class);
|
||||
|
||||
@Override
|
||||
public RemoteRancherService create(Throwable throwable) {
|
||||
log.error("Rancher服务调用失败:{}", throwable.getMessage());
|
||||
|
||||
return new RemoteRancherService() {
|
||||
@Override
|
||||
public Response getK8sNamespaceList(String cluster_id, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sDaemonsetsList(String cluster_id, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sDeployList(String cluster_id, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sStatefulList(String cluster_id, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sClusterNodeList(String cluster_id, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sApplicationDetail(String cluster_id, String fullKind, String namespace, String applicationName, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sPodListByNamespace(String cluster_id, String namespace, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sPodList(String cluster_id, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sServiceByApplicationId(String cluster_id, String nginxApplicationId, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response deletePod(String namespace, String podName, JSONObject deletePodBody, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response updateK8sApplication(String fullKind, String namespace, String applicationName, JSONObject applicationDetail, String userKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response createK8sApplication(String fullName, String yamlContent, String userKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response applyK8sYaml(String cluster_id, JSONObject yamlContent, String userKey) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getApplicationYamlFile(String kindName, String namespace, String applicationName, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response editK8sApplication(String fullKind, String namespace, String applicationName, String yamlContent, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response deleteApplication(String fullKind, String namespace, String applicationName, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sConfigmapByNamespace(String namespace, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sSecretByNamespace(String namespace, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response getK8sServiceByNamespace(String cluster_id, String namespace, String token) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response deleteK8sService(String serviceId, String token) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.microservices.system.api.model;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class GraphqlQueryVo {
|
||||
String operationName;
|
||||
String query;
|
||||
JSONObject variables;
|
||||
}
|
||||
|
|
@ -3,20 +3,24 @@ package com.microservices.system.api.utils;
|
|||
import com.microservices.common.core.domain.R;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import feign.Response;
|
||||
|
||||
/**
|
||||
* @author otto
|
||||
*/
|
||||
public class FeignUtils {
|
||||
public static <T> T getReturnData(R<T> result){
|
||||
public static <T> T getReturnData(R<T> result) {
|
||||
if (StringUtils.isNull(result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (R.FAIL == result.getCode())
|
||||
{
|
||||
if (R.FAIL == result.getCode()) {
|
||||
throw new ServiceException(result.getMsg());
|
||||
}
|
||||
return result.getData();
|
||||
}
|
||||
|
||||
public static Boolean isSuccess(Response response) {
|
||||
return response != null && response.status() >= 200 && response.status() < 300;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,3 +6,4 @@ com.microservices.system.api.factory.RemoteCmsFallbackFactory
|
|||
com.microservices.system.api.factory.RemoteZoneFallbackFactory
|
||||
com.microservices.system.api.factory.RemotePmsFallbackFactory
|
||||
com.microservices.system.api.factory.RemoteGatewayFallbackFactory
|
||||
com.microservices.system.api.factory.RemoteRancherFallbackFactory
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9110
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -213,6 +213,11 @@ public class CacheConstants {
|
|||
*/
|
||||
public final static String SENTINEL_TOKEN = "sentinel_token";
|
||||
|
||||
/**
|
||||
* Rancher Token缓存Key
|
||||
*/
|
||||
public final static String RANCHER_TOKEN = "rancher_token";
|
||||
|
||||
|
||||
/**
|
||||
* Nacos Token缓存Key
|
||||
|
|
|
|||
|
|
@ -5,8 +5,7 @@ package com.microservices.common.core.constant;
|
|||
*
|
||||
* @author microservices
|
||||
*/
|
||||
public class Constants
|
||||
{
|
||||
public class Constants {
|
||||
/**
|
||||
* UTF-8 字符集
|
||||
*/
|
||||
|
|
@ -125,6 +124,10 @@ public class Constants
|
|||
* JSON类型
|
||||
*/
|
||||
public static final String JSON_CONTENT_TYPE = "application/json";
|
||||
/**
|
||||
* Yaml类型
|
||||
*/
|
||||
public static final String YAML_CONTENT_TYPE = "application/yaml";
|
||||
/**
|
||||
* 文本类型
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -37,6 +37,11 @@ public class SecurityConstants
|
|||
*/
|
||||
public static final String USER_KEY = "user_key";
|
||||
|
||||
/**
|
||||
* 用户Token
|
||||
*/
|
||||
public static final String TOKEN = "token";
|
||||
|
||||
/**
|
||||
* 组织ID
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -22,9 +22,16 @@ public class TokenConstants {
|
|||
* Sentinel令牌标识
|
||||
*/
|
||||
public static final String Sentinel_Token_Key = "sentinel_dashboard_cookie";
|
||||
/**
|
||||
* Rancher令牌标识
|
||||
*/
|
||||
public static final String Rancher_Cookie_Token_Key = "R_SESS";
|
||||
/**
|
||||
* Portainer令牌标识
|
||||
*/
|
||||
public static final String Portainer_Token_Key = "portainer_api_key";
|
||||
/**
|
||||
* Sentinel令牌标识
|
||||
* Nacos令牌标识
|
||||
*/
|
||||
public static final String Nacos_Token_Key = "Accesstoken";
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
package com.microservices.common.core.threadPool;
|
||||
|
||||
import com.microservices.common.core.constant.TokenConstants;
|
||||
import com.microservices.common.core.context.SecurityContextHolder;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
|
@ -37,6 +38,9 @@ public class ThreadPoolExecutorWrap extends ThreadPoolExecutor {
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
if(contextValue != null&&contextValue.containsKey("user_key")){
|
||||
contextValue.put(TokenConstants.AUTHENTICATION, contextValue.get("user_key"));
|
||||
}
|
||||
SecurityContextHolder.setLocalMap(contextValue);
|
||||
// 用户任务逻辑
|
||||
task.run();
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ public class GenericsTableDataInfo<T> implements Serializable {
|
|||
/**
|
||||
* 面包屑数据
|
||||
*/
|
||||
@ApiModelProperty("面包屑数据")
|
||||
@ApiModelProperty(value = "面包屑数据",hidden = true)
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) //为空时隐藏
|
||||
private List<Breadcrumb> breadcrumb;
|
||||
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ public class GitLinkRequestHelper {
|
|||
HashMap<String, String> headers = prepareAuthenticationHeaders(gitLinkRequestUrl);
|
||||
String requestId = UUID.randomUUID().toString();
|
||||
String path = gitLinkRequestUrl.getPath();
|
||||
logger.info("[{}]通过HttpClient向平台发起请求,请求方法为:{},请求网站为:{},请求路由为:{},请求载体为:{},请求头为:{}"
|
||||
logger.debug("[{}]通过HttpClient向平台发起请求,请求方法为:{},请求网站为:{},请求路由为:{},请求载体为:{},请求头为:{}"
|
||||
, requestId
|
||||
, requestType
|
||||
, gitLinkUrl
|
||||
|
|
@ -111,7 +111,7 @@ public class GitLinkRequestHelper {
|
|||
default:
|
||||
throw new ServiceException("不支持该请求方式:" + requestType.name());
|
||||
}
|
||||
logger.info("[{}]请求响应为:{}"
|
||||
logger.debug("[{}]请求响应为:{}"
|
||||
, requestId
|
||||
, result);
|
||||
} catch (Exception e) {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,12 @@
|
|||
<artifactId>microservices-common-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package com.microservices.common.security.handler;
|
||||
|
||||
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
|
||||
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.domain.R;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class SentinelBlockExceptionHandler implements BlockExceptionHandler {
|
||||
|
||||
@Override
|
||||
public void handle(HttpServletRequest request,
|
||||
HttpServletResponse response,
|
||||
BlockException ex) throws Exception {
|
||||
|
||||
R<?> body;
|
||||
if (ex instanceof FlowException) { // 限流
|
||||
body = R.fail(429, "请求过于频繁,请稍后重试");
|
||||
} else if (ex instanceof DegradeException) { // 熔断
|
||||
body = R.fail(500, "服务暂时不可用,请稍后重试");
|
||||
} else if (ex instanceof ParamFlowException) { // 热点参数限流
|
||||
body = R.fail(400, "热点参数限流");
|
||||
} else if (ex instanceof AuthorityException) { // 授权规则
|
||||
body = R.fail(403, "无权限访问该资源");
|
||||
} else if (ex instanceof SystemBlockException) { // 系统规则
|
||||
body = R.fail(500, "系统规则限制,无法访问");
|
||||
} else { // 兜底
|
||||
body = R.fail(500, "服务繁忙,请稍后重试");
|
||||
}
|
||||
|
||||
response.setStatus(HttpStatus.OK.value());
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.setCharacterEncoding("UTF-8");
|
||||
response.getWriter().write(JSONObject.toJSONString(body));
|
||||
}
|
||||
}
|
||||
|
|
@ -4,3 +4,4 @@ com.microservices.common.security.service.impl.RequestCustomServiceImpl
|
|||
com.microservices.common.security.aspect.PreAuthorizeAspect
|
||||
com.microservices.common.security.aspect.InnerAuthAspect
|
||||
com.microservices.common.security.handler.GlobalExceptionHandler
|
||||
com.microservices.common.security.handler.SentinelBlockExceptionHandler
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
try {
|
||||
claims = JwtUtils.parseToken(token);
|
||||
} catch (Exception e) {
|
||||
log.error("令牌解析失败:{}", e.getMessage());
|
||||
log.error("[鉴权异常处理]令牌解析失败:{}", e.getMessage());
|
||||
return unauthorizedResponse(exchange, "令牌格式不正确!");
|
||||
}
|
||||
if (claims == null) {
|
||||
|
|
@ -139,7 +139,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
);
|
||||
redisService.setCacheObject(redisKey, feignResult);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户【{}】身份列表时发生异常:{}", username, e.getMessage());
|
||||
log.error("[鉴权异常处理]获取用户【{}】身份列表时发生异常:{}", username, e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -167,7 +167,7 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
}
|
||||
return genCookieByToken(token);
|
||||
} catch (Exception e) {
|
||||
log.error("检查该gitlink token【{}】是否登录时发生异常:{}", token, e.getMessage());
|
||||
log.error("[鉴权异常处理]检查该token【{}】是否登录时发生异常:{}", token, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -215,11 +215,11 @@ public class AuthFilter implements GlobalFilter, Ordered {
|
|||
try {
|
||||
feignResult = future.get();
|
||||
} catch (Exception e) {
|
||||
log.error("异步请求获取本系统Token出错:{}", e.getMessage());
|
||||
log.error("[鉴权异常处理]异步请求获取本系统Token出错:{}", e.getMessage());
|
||||
throw new ServiceException("内部服务错误");
|
||||
}
|
||||
if (StringUtils.isNull(feignResult) || R.FAIL == feignResult.getCode()) {
|
||||
log.error("Token获取出错:{}", feignResult.getMsg());
|
||||
log.error("[鉴权异常处理]Token获取出错:{}", feignResult.getMsg());
|
||||
throw new ServiceException("内部服务错误");
|
||||
}
|
||||
if (R.SUCCESS == feignResult.getCode()) {
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
String lowerUrl = request.getURI().getPath().toLowerCase();
|
||||
ServerHttpResponse originalResponse = exchange.getResponse();
|
||||
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
|
||||
|
||||
// 当请求为Nacos时,Nacos返回的所有非JSON响应都会被自动转换为结构化的错误信息,同时将HTTP状态码设置为200,适合用于规范化微服务架构的响应格式。
|
||||
if (lowerUrl.startsWith("/nacos")) {
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
return super.writeWith(body);
|
||||
}
|
||||
if (status == HttpStatus.FORBIDDEN) {
|
||||
log.error("nacos鉴权异常,已清理redis中nacos token");
|
||||
log.error("[网关转发异常处理]nacos鉴权异常,已清理redis中nacos token");
|
||||
// 设置新的状态码为 200
|
||||
setStatusCode(HttpStatus.OK);
|
||||
// 设置响应内容类型为 JSON
|
||||
|
|
@ -125,7 +126,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
}
|
||||
synchronousSink.complete();
|
||||
}).flatMap(resStr -> {
|
||||
log.error("Portainer响应处理异常,异常信息:{}", resStr);
|
||||
log.error("[网关转发异常处理]Portainer响应处理异常,异常信息:{}", resStr);
|
||||
originalResponse.setStatusCode(HttpStatus.OK);
|
||||
byte[] bytes;
|
||||
if (JSON.isValid(resStr)) {
|
||||
|
|
@ -133,7 +134,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
if (resJson.containsKey("message")) {
|
||||
String message = resJson.getString("message");
|
||||
if (StringUtils.isNotBlank(message) && message.contains("A valid authorisation token is missing")) {
|
||||
log.error("Portainer鉴权异常,已清理redis中Portainer token");
|
||||
log.error("[网关转发异常处理]Portainer鉴权异常,已清理redis中Portainer token");
|
||||
//token失效清除redis缓存
|
||||
redisService.deleteObject(CacheConstants.PORTAINER_TOKEN);
|
||||
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.RETRY_ERROR));
|
||||
|
|
@ -160,12 +161,12 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
|
||||
@Override
|
||||
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
|
||||
HttpStatus status = getStatusCode() != null ? getStatusCode() : HttpStatus.INTERNAL_SERVER_ERROR;
|
||||
HttpStatus status = getStatusCode();
|
||||
if (!status.isError()) {
|
||||
return super.writeWith(body);
|
||||
}
|
||||
if (status == HttpStatus.UNAUTHORIZED) {
|
||||
log.error("sentinel鉴权异常,已清理redis中sentinel token");
|
||||
log.error("[网关转发异常处理]sentinel鉴权异常,已清理redis中sentinel token");
|
||||
// 设置新的状态码为 200
|
||||
setStatusCode(HttpStatus.OK);
|
||||
// 设置响应内容类型为 JSON
|
||||
|
|
@ -192,7 +193,7 @@ public class GlobalResponseFilter implements GlobalFilter, Ordered {
|
|||
}
|
||||
synchronousSink.complete();
|
||||
}).flatMap(resStr -> {
|
||||
log.error("Sentinel响应处理异常,异常信息:{}", resStr);
|
||||
log.error("[网关转发异常处理]Sentinel响应处理异常,异常信息:{}", resStr);
|
||||
byte[] bytes;
|
||||
bytes = JSON.toJSONBytes(AjaxResult.error(ExceptionMsgConstants.SYSTEM_EXEC_ERROR));
|
||||
setStatusCode(HttpStatus.OK);
|
||||
|
|
|
|||
|
|
@ -53,8 +53,14 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
public String portainerUsername;
|
||||
@Value("${thirdPartyTools.portainer.auth.password:}")
|
||||
public String portainerPassword;
|
||||
@Value("${thirdPartyTools.rancher.auth.username:}")
|
||||
public String rancherUsername;
|
||||
@Value("${thirdPartyTools.rancher.auth.password:}")
|
||||
public String rancherPassword;
|
||||
@Value("${thirdPartyTools.portainer.endpoints:}")
|
||||
public Integer portainerEndpoints;
|
||||
@Value("${thirdPartyTools.retryTimes:1}")
|
||||
public Integer retryTimes;
|
||||
ThreadPoolExecutor threadPoolExecutor = CustomExecutorFactory.threadPoolExecutor;
|
||||
@Lazy
|
||||
@Autowired
|
||||
|
|
@ -83,27 +89,81 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
if (redisService.hasKey(CacheConstants.SENTINEL_TOKEN)) {
|
||||
sentinelCookie = redisService.getCacheObject(CacheConstants.SENTINEL_TOKEN);
|
||||
} else {
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel(sentinelUsername, sentinelPassword));
|
||||
try {
|
||||
Response response = future.get(1, TimeUnit.SECONDS);
|
||||
Map<String, Collection<String>> header = response.headers();
|
||||
if (header != null && header.containsKey("set-cookie")) {
|
||||
sentinelCookie = header.get("set-cookie").iterator().next();
|
||||
//Sentinel登录状态默认30分钟失效,将Sentinel Token缓存过期时间调整为28分钟
|
||||
redisService.setCacheObject(CacheConstants.SENTINEL_TOKEN, sentinelCookie, 28L, TimeUnit.MINUTES);
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Sentinel Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginSentinel(sentinelUsername, sentinelPassword));
|
||||
try {
|
||||
Response response = future.get(3, TimeUnit.SECONDS);
|
||||
Map<String, Collection<String>> header = response.headers();
|
||||
if (header != null && header.containsKey("set-cookie")) {
|
||||
sentinelCookie = header.get("set-cookie").iterator().next();
|
||||
//Sentinel登录状态默认30分钟失效,将Sentinel Token缓存过期时间调整为28分钟
|
||||
redisService.setCacheObject(CacheConstants.SENTINEL_TOKEN, sentinelCookie, 28L, TimeUnit.MINUTES);
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("[网关转发异常处理]获取Sentinel Token超时");
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("[网关转发异常处理]获取Sentinel Token失败:{}", e.getMessage());
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("获取Sentinel Token超时");
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("获取Sentinel Token失败:{}", e.getMessage());
|
||||
|
||||
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
||||
break;
|
||||
}
|
||||
|
||||
log.warn("[网关转发异常处理]获取Sentinel Token失败,进行第{}次重试中", i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (StringUtils.isNotEmpty(sentinelCookie)) {
|
||||
ServletUtils.removeHeader(mutate, TokenConstants.Cookie);
|
||||
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, sentinelCookie));
|
||||
} else {
|
||||
throw new ServiceException("Sentinel服务获取Token失败");
|
||||
throw new ServiceException("[网关转发异常处理]Sentinel服务获取Token失败");
|
||||
}
|
||||
}
|
||||
|
||||
// 处理Rancher请求
|
||||
if (lowerUrl.startsWith("/rancher")) {
|
||||
String rancherToken = null;
|
||||
if (redisService.hasKey(CacheConstants.RANCHER_TOKEN)) {
|
||||
rancherToken = redisService.getCacheObject(CacheConstants.RANCHER_TOKEN);
|
||||
} else {
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
JSONObject loginRancherBody = new JSONObject();
|
||||
loginRancherBody.put("description", "api session");
|
||||
loginRancherBody.put("responseType", "cookie");
|
||||
loginRancherBody.put("username", rancherUsername);
|
||||
loginRancherBody.put("password", rancherPassword);
|
||||
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Rancher Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginRancher(loginRancherBody));
|
||||
try {
|
||||
Response response = future.get(3, TimeUnit.SECONDS);
|
||||
Map<String, Collection<String>> header = response.headers();
|
||||
if (header != null && header.containsKey("set-cookie")) {
|
||||
String rancherCookie = header.get("set-cookie").iterator().next();
|
||||
rancherToken = getValueByCookieKey(rancherCookie, TokenConstants.Rancher_Cookie_Token_Key);
|
||||
//Rancher登录状态默认15小时失效,将Rancher Token缓存过期时间调整为14分钟
|
||||
redisService.setCacheObject(CacheConstants.RANCHER_TOKEN, rancherToken, 14L, TimeUnit.HOURS);
|
||||
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("[网关转发异常处理]获取Rancher Token超时");
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
log.error("[网关转发异常处理]获取Rancher Token失败:{}", e.getMessage());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(rancherToken)) {
|
||||
break;
|
||||
}
|
||||
|
||||
log.warn("[网关转发异常处理]获取Rancher Token失败,进行第{}次重试中", i + 1);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotEmpty(rancherToken)) {
|
||||
ServletUtils.removeHeader(mutate, TokenConstants.AUTHENTICATION);
|
||||
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + rancherToken);
|
||||
} else {
|
||||
throw new ServiceException("[网关转发异常处理]Rancher服务获取Token失败");
|
||||
}
|
||||
}
|
||||
// 处理Nacos请求
|
||||
|
|
@ -112,38 +172,44 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
if (redisService.hasKey(CacheConstants.NACOS_TOKEN)) {
|
||||
nacosToken = redisService.getCacheObject(CacheConstants.NACOS_TOKEN);
|
||||
} else {
|
||||
Map<String, String> nacosMap = new HashMap<>();
|
||||
nacosMap.put("username", nacosUsername);
|
||||
nacosMap.put("password", nacosPassword);
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Nacos Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
|
||||
try {
|
||||
Response res = future.get(1, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
for (int i = 0; i < retryTimes; i++) {
|
||||
Map<String, String> nacosMap = new HashMap<>();
|
||||
nacosMap.put("username", nacosUsername);
|
||||
nacosMap.put("password", nacosPassword);
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Nacos Token
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginNacos(nacosMap));
|
||||
try {
|
||||
Response res = future.get(3, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
if (resJsonObject == null) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
nacosToken = resJsonObject.getString("accessToken");
|
||||
Long tokenTtl = resJsonObject.getLong("tokenTtl");
|
||||
if (nacosToken != null && tokenTtl != null) {
|
||||
redisService.setCacheObject(CacheConstants.NACOS_TOKEN, nacosToken, tokenTtl - 10, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("[网关转发异常处理]获取Nacos Token超时");
|
||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||
log.error("[网关转发异常处理]获取Nacos Token失败:{}", e.getMessage());
|
||||
}
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
if (resJsonObject == null) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
if (StringUtils.isNotEmpty(nacosToken)) {
|
||||
break;
|
||||
}
|
||||
nacosToken = resJsonObject.getString("accessToken");
|
||||
Long tokenTtl = resJsonObject.getLong("tokenTtl");
|
||||
if (nacosToken != null && tokenTtl != null) {
|
||||
redisService.setCacheObject(CacheConstants.NACOS_TOKEN, nacosToken, tokenTtl - 10, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("获取Nacos Token超时");
|
||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||
log.error("获取Nacos Token失败:{}", e.getMessage());
|
||||
log.warn("[网关转发异常处理]获取Nacos Token失败,进行第{}次重试中", i + 1);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotEmpty(nacosToken)) {
|
||||
mutate.header(TokenConstants.Nacos_Token_Key, nacosToken);
|
||||
} else {
|
||||
throw new ServiceException("Nacos服务获取Token失败");
|
||||
throw new ServiceException("[网关转发异常处理]Nacos服务获取Token失败");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -163,7 +229,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
try {
|
||||
mutate.uri(new URI(url));
|
||||
} catch (URISyntaxException e) {
|
||||
log.error("替换Portainer请求中Endpoints时发生异常:{}", e.getMessage());
|
||||
log.error("[网关转发异常处理]替换Portainer请求中Endpoints时发生异常:{}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -178,38 +244,44 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
if (redisService.hasKey(CacheConstants.PORTAINER_TOKEN)) {
|
||||
portainerToken = redisService.getCacheObject(CacheConstants.PORTAINER_TOKEN);
|
||||
} else {
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Portainer Token
|
||||
JSONObject loginPortainerBody = new JSONObject();
|
||||
loginPortainerBody.put("username", portainerUsername);
|
||||
loginPortainerBody.put("password", portainerPassword);
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginPortainer(loginPortainerBody));
|
||||
try {
|
||||
Response res = future.get(1, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
portainerToken = resJsonObject.getString("jwt");
|
||||
if (portainerToken == null) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
String[] tokenSplit = portainerToken.split("\\.");
|
||||
String tokenBodyStr = new String(Base64.getDecoder().decode(tokenSplit[1]), StandardCharsets.UTF_8);
|
||||
JSONObject tokenBody = JSONObject.parseObject(tokenBodyStr);
|
||||
Long expiration = tokenBody.getLong("exp");
|
||||
Long now = new Date().getTime() / 1000;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
// 网关采用异步架构,所以此处需要通过异步请求获取Portainer Token
|
||||
JSONObject loginPortainerBody = new JSONObject();
|
||||
loginPortainerBody.put("username", portainerUsername);
|
||||
loginPortainerBody.put("password", portainerPassword);
|
||||
Future<Response> future = threadPoolExecutor.submit(() -> remoteGatewayService.loginPortainer(loginPortainerBody));
|
||||
try {
|
||||
Response res = future.get(1, TimeUnit.SECONDS);
|
||||
StringWriter writer = new StringWriter();
|
||||
IOUtils.copy(res.body().asInputStream(), writer, StandardCharsets.UTF_8.name());
|
||||
String str = writer.toString();
|
||||
if (!JSON.isValid(str)) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
JSONObject resJsonObject = JSONObject.parseObject(str);
|
||||
portainerToken = resJsonObject.getString("jwt");
|
||||
if (portainerToken == null) {
|
||||
return exceptionResponse(exchange, str, res.status());
|
||||
}
|
||||
String[] tokenSplit = portainerToken.split("\\.");
|
||||
String tokenBodyStr = new String(Base64.getDecoder().decode(tokenSplit[1]), StandardCharsets.UTF_8);
|
||||
JSONObject tokenBody = JSONObject.parseObject(tokenBodyStr);
|
||||
Long expiration = tokenBody.getLong("exp");
|
||||
Long now = new Date().getTime() / 1000;
|
||||
|
||||
long portainerTokenTtl = expiration - now;
|
||||
if (portainerTokenTtl > 20) {
|
||||
redisService.setCacheObject(CacheConstants.PORTAINER_TOKEN, portainerToken, portainerTokenTtl - 10, TimeUnit.SECONDS);
|
||||
long portainerTokenTtl = expiration - now;
|
||||
if (portainerTokenTtl > 20) {
|
||||
redisService.setCacheObject(CacheConstants.PORTAINER_TOKEN, portainerToken, portainerTokenTtl - 10, TimeUnit.SECONDS);
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("[网关转发异常处理]获取Portainer Token超时");
|
||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||
log.error("[网关转发异常处理]获取Portainer Token失败:{}", e.getMessage());
|
||||
}
|
||||
} catch (TimeoutException e) {
|
||||
log.error("获取Portainer Token超时");
|
||||
} catch (InterruptedException | ExecutionException | IOException | NullPointerException e) {
|
||||
log.error("获取Portainer Token失败:{}", e.getMessage());
|
||||
if (StringUtils.isNotEmpty(portainerToken)) {
|
||||
break;
|
||||
}
|
||||
log.warn("[网关转发异常处理]获取Portainer Token失败,进行第{}次重试中", i + 1);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotEmpty(portainerToken)) {
|
||||
|
|
@ -218,7 +290,7 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
mutate.header(TokenConstants.AUTHENTICATION, TokenConstants.PREFIX + portainerToken);
|
||||
mutate.header(TokenConstants.Cookie, String.format("%s;%s;", cookie, portainerToken));
|
||||
} else {
|
||||
throw new ServiceException("Portainer服务获取Token失败");
|
||||
throw new ServiceException("[网关转发异常处理]Portainer服务获取Token失败");
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
|
@ -226,7 +298,23 @@ public class ThirdPartyToolServiceImpl implements ThirdPartyToolService {
|
|||
|
||||
|
||||
private Mono<Void> exceptionResponse(ServerWebExchange exchange, String msg, int code) {
|
||||
log.error("[第三方工具请求处理异常]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), msg);
|
||||
log.error("[网关转发异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), msg);
|
||||
return ServletUtils.webFluxResponseWriter(exchange.getResponse(), ExceptionMsgConstants.SYSTEM_EXEC_ERROR, code);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过指定Key获取Cookie中指定值
|
||||
*/
|
||||
private static String getValueByCookieKey(String cookie, String key) {
|
||||
if (cookie != null) {
|
||||
String[] cookies = StringUtils.split(cookie, ';');
|
||||
for (String cookieItem : cookies) {
|
||||
if (cookieItem.contains(key)) {
|
||||
String token = StringUtils.remove(cookieItem, key + "=");
|
||||
return StringUtils.remove(token, " ");
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ public class CmsDocController extends BaseController {
|
|||
public AjaxResult editCmsDIr(@ApiParam(name = "id", value = "栏目Id") @PathVariable Long id,
|
||||
@ApiParam(name = "cmsDirUpdateVo", value = "栏目更新对象") @RequestBody CmsDirUpdateVo cmsDirUpdateVo) {
|
||||
cmsDocService.updateCmsDir(id, cmsDirUpdateVo);
|
||||
return success("异步更新栏目信息");
|
||||
return success("栏目信息更新成功");
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ public class OpenController extends BaseController {
|
|||
public GenericsTableDataInfo<CmsDocBaseDto> docList(@ApiParam(name = "dirId", value = "栏目Id") @PathVariable("dirId") Long dirId
|
||||
, CmsDocSearchVo cmsDocSearchVo) {
|
||||
cmsDocSearchVo.setIsOpen(true);
|
||||
List<CmsDocBaseDto> list = cmsDocService.selectCmsDocList(dirId, cmsDocSearchVo);
|
||||
List<CmsDocBaseDto> list = cmsDocService.selectSetDefaultHeadImgCmsDocList(dirId, cmsDocSearchVo);
|
||||
return getAllGenericsDataTableToPage(list);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ public class CmsDir implements Comparable<CmsDir> {
|
|||
@ApiModelProperty(value = "排序", hidden = true)
|
||||
private Integer sort;
|
||||
|
||||
@ApiModelProperty(value = "文章头图")
|
||||
private String headImg;
|
||||
|
||||
public String getName() {
|
||||
if (name != null) {
|
||||
name = name.replaceAll(CmsConstants.DIR_SEPARATOR,
|
||||
|
|
|
|||
|
|
@ -21,9 +21,6 @@ public class CmsDirUpdateVo {
|
|||
@ApiModelProperty(value = "顺序")
|
||||
private Integer order;
|
||||
|
||||
public CmsDir toCmsDir() {
|
||||
CmsDir cmsDir = new CmsDir();
|
||||
cmsDir.setName(name);
|
||||
return cmsDir;
|
||||
}
|
||||
@ApiModelProperty(value = "文章头图")
|
||||
private String headImg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -166,6 +166,7 @@ public class CmsDoc extends BaseSortEntity {
|
|||
CmsDir cmsDir = new CmsDir();
|
||||
cmsDir.setId(id);
|
||||
cmsDir.setName(name);
|
||||
cmsDir.setHeadImg(headImg);
|
||||
cmsDir.setSort(this.getSort());
|
||||
cmsDir.setCreatedAt(getCreateTime());
|
||||
return cmsDir;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
package com.microservices.cms.doc.domain.gitlink;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
|
|
@ -22,4 +24,12 @@ public class EntryDto implements Comparable<EntryDto> {
|
|||
// 重写Comparable接口的compareTo方法,根据年龄升序排列,降序修改相减顺序即可
|
||||
return Math.toIntExact(entryDto.getCommit().getCreated_at_unix() - this.commit.getCreated_at_unix());
|
||||
}
|
||||
|
||||
public static EntryDto getEntryDtoFromJson(JSONObject subEntriesResult) {
|
||||
FileEntryDto fileEntryDto = subEntriesResult.toJavaObject(FileEntryDto.class);
|
||||
if (fileEntryDto == null || fileEntryDto.getEntries() == null) {
|
||||
throw new ServiceException("该文章不存在");
|
||||
}
|
||||
return fileEntryDto.getEntries();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,17 @@ public interface CmsDocMapper {
|
|||
*/
|
||||
public List<CmsDoc> selectCmsDocList(CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 查询文章信息列表(设置默认头图为栏目头图)
|
||||
*
|
||||
* @param cmsDocSearchVo 文章信息
|
||||
* @return 文章信息集合
|
||||
*/
|
||||
List<CmsDoc> selectCmsDocListSetDefaultHeadImg(CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
|
||||
/**
|
||||
* 新增文章信息
|
||||
*
|
||||
|
|
@ -172,4 +183,13 @@ public interface CmsDocMapper {
|
|||
Long getNotAuditCmsCountByDeptId(Long deptId);
|
||||
|
||||
Long getCmsDocVisitsByDeptId(Long deptId);
|
||||
|
||||
/**
|
||||
* 根据组织id获取专区下所有文章和栏目
|
||||
* @param deptId 组织id
|
||||
* @return 文章和栏目列表
|
||||
*/
|
||||
List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId);
|
||||
|
||||
void updateCmsDocShaByPathAndDeptId(@Param("sha") String sha, @Param("filePath") String filePath, @Param("deptId") Long deptId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public interface ICmsAsyncService {
|
|||
|
||||
void asyncCreateBranchAndDeleteFileAndCreatePR(CmsDoc newDocWithAudit, CmsProject cmsProject);
|
||||
|
||||
void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir);
|
||||
void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, String newCmsDirName);
|
||||
|
||||
/**
|
||||
* 推送文章数据到搜索引擎
|
||||
|
|
|
|||
|
|
@ -288,4 +288,10 @@ public interface ICmsDocService {
|
|||
CmsDocBaseDto selectCmsDocBaseInfoById(Long id);
|
||||
|
||||
Long getCmsDocVisitsByDeptId(Long deptId);
|
||||
|
||||
List<CmsDocBaseDto> selectSetDefaultHeadImgCmsDocList(Long dirId, CmsDocSearchVo cmsDocSearchVo);
|
||||
|
||||
List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId);
|
||||
|
||||
void updateCmsDocShaByPathAndDeptId(String sha, String filePath, Long deptId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.microservices.cms.project.service.ICmsProjectService;
|
|||
import com.microservices.cms.utils.CmsConstants;
|
||||
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
||||
import com.microservices.cms.utils.CmsUtils;
|
||||
import com.microservices.cms.utils.CustomExecutorFactory;
|
||||
import com.microservices.common.core.constant.CacheConstants;
|
||||
import com.microservices.common.core.constant.Constants;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
|
|
@ -24,6 +25,7 @@ import com.microservices.common.core.exception.ServiceException;
|
|||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.utils.html.EscapeUtil;
|
||||
import com.microservices.common.core.utils.sign.Base64;
|
||||
import com.microservices.common.core.utils.uuid.IdUtils;
|
||||
import com.microservices.common.httpClient.constant.GitLinkConstants;
|
||||
import com.microservices.common.httpClient.service.HttpAPIService;
|
||||
|
|
@ -47,6 +49,7 @@ import org.springframework.util.DigestUtils;
|
|||
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -93,6 +96,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
private RemoteZoneService remoteZoneService;
|
||||
@Autowired
|
||||
private RequestConfig config;
|
||||
|
||||
/**
|
||||
* 异步设置文章更新时间
|
||||
*
|
||||
|
|
@ -109,7 +113,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
} else {
|
||||
redisService.setCacheObject(updateDocIntervalKey, cmsProject.getName(), 1L, TimeUnit.MINUTES);
|
||||
}
|
||||
CmsDocSearchVo cmsDocSearch=new CmsDocSearchVo();
|
||||
CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
|
||||
cmsDocSearch.setDeptId(cmsProject.getDeptId());
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
||||
for (EntryDto entryDto : entryDtoList) {
|
||||
|
|
@ -150,7 +154,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
webhook.put("eventCondition", "push");
|
||||
webhook.put("http_method", "POST");
|
||||
webhook.put("secret", "");
|
||||
webhook.put("url", gatewayUrl+"/cms/doc/open/dept/"+cmsProject.getDeptId());
|
||||
webhook.put("url", gatewayUrl + "/cms/doc/open/dept/" + cmsProject.getDeptId());
|
||||
webhook.put("events", new String[]{"push"});
|
||||
jsonObject.put("webhook", webhook);
|
||||
//增加Webhook
|
||||
|
|
@ -231,7 +235,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
|
||||
private void syncDocAddedData(CmsProject cmsProject, List<String> addedList) {
|
||||
for (String addedFilePath:addedList) {
|
||||
for (String addedFilePath : addedList) {
|
||||
try {
|
||||
String[] filePathList = addedFilePath.split("/");
|
||||
if (filePathList.length != 2) {
|
||||
|
|
@ -250,15 +254,15 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
syncCreateDoc(entry, dirName, cmsProject.getDeptId(), fileEntry.getLast_commit());
|
||||
}
|
||||
}
|
||||
}catch (Exception e){
|
||||
} catch (Exception e) {
|
||||
logger.error("[{}]同步新增文章发生异常:{}"
|
||||
, cmsProject.getName(), e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void syncDocRemovedData(CmsProject cmsProject,List<String> removedList) {
|
||||
for (String removedFilePath:removedList) {
|
||||
private void syncDocRemovedData(CmsProject cmsProject, List<String> removedList) {
|
||||
for (String removedFilePath : removedList) {
|
||||
try {
|
||||
String[] filePathList = removedFilePath.split("/");
|
||||
if (filePathList.length != 2) {
|
||||
|
|
@ -357,7 +361,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
cmsDocSearch.setDeptId(cmsDir.getDeptId());
|
||||
cmsDocSearch.setDirName(cmsDir.getName());
|
||||
cmsDocSearch.setIsDir(false);
|
||||
List<CmsDoc> cmsDocList=cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
||||
//获取数据库所有文件的filePath
|
||||
List<String> databaseFilePathList = cmsDocList.stream().map(CmsDoc::getFilePath).collect(Collectors.toList());
|
||||
//获取需要新增的文章
|
||||
|
|
@ -383,16 +387,16 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
@Override
|
||||
public void asyncDocData(Long deptId, String bodyStr) {
|
||||
//防止多次操作同时执行,将同步内容放入队列,根据先后时间执行同步动作
|
||||
String cmsSyncDeptIdKey=CacheConstants.CMS_SYNC_DEPT_ID_KEY+deptId;
|
||||
String cmsSyncDeptIdKey = CacheConstants.CMS_SYNC_DEPT_ID_KEY + deptId;
|
||||
//为当前同步操作生成UUID,若拿到的UUID为自身,则执行本次同步动作
|
||||
String UUID= IdUtils.fastSimpleUUID();
|
||||
String UUID = IdUtils.fastSimpleUUID();
|
||||
redisService.leftPush(cmsSyncDeptIdKey, UUID);
|
||||
//设置缓存过期时间,防止异常情况导致同步无法继续执行
|
||||
redisService.expire(cmsSyncDeptIdKey, 3600, TimeUnit.SECONDS);
|
||||
String currentUUID = String.valueOf(redisService.listIndexOf(cmsSyncDeptIdKey, -1));
|
||||
//设置最大循环阈值,防止意外情况导致死循环(7200次,约1小时左右)
|
||||
int threshold=7200;
|
||||
while (!UUID.equals(currentUUID)&&threshold!=0){
|
||||
int threshold = 7200;
|
||||
while (!UUID.equals(currentUUID) && threshold != 0) {
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
|
|
@ -402,41 +406,41 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
threshold--;
|
||||
}
|
||||
|
||||
try{
|
||||
CmsProject cmsProject=cmsProjectService.selectCmsProjectByDeptId(deptId);
|
||||
JSONObject body=JSONObject.parseObject(bodyStr);
|
||||
try {
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(deptId);
|
||||
JSONObject body = JSONObject.parseObject(bodyStr);
|
||||
//获取本次推送中Commit总数
|
||||
Integer totalCommits=body.getInteger("total_commits");
|
||||
Integer totalCommits = body.getInteger("total_commits");
|
||||
//从webhook请求中获取本次提交内容
|
||||
JSONArray commits=body.getJSONArray("commits");
|
||||
JSONArray commits = body.getJSONArray("commits");
|
||||
//当commit总数大于提交的列表数量时,代表此次PUSH未携带所有commit,此时进行一次全量同步
|
||||
if(totalCommits!=null
|
||||
&&commits!=null
|
||||
&&totalCommits>commits.size()){
|
||||
if (totalCommits != null
|
||||
&& commits != null
|
||||
&& totalCommits > commits.size()) {
|
||||
fullSyncDocData(cmsProject);
|
||||
}else{
|
||||
for (int i = commits.size()-1; i >=0 ; i--) {
|
||||
JSONObject commit=commits.getJSONObject(i);
|
||||
} else {
|
||||
for (int i = commits.size() - 1; i >= 0; i--) {
|
||||
JSONObject commit = commits.getJSONObject(i);
|
||||
//获取新增的文件列表
|
||||
JSONArray addedList=commit.getJSONArray("added");
|
||||
if(addedList!=null){
|
||||
syncDocAddedData(cmsProject,addedList.toJavaList(String.class));
|
||||
JSONArray addedList = commit.getJSONArray("added");
|
||||
if (addedList != null) {
|
||||
syncDocAddedData(cmsProject, addedList.toJavaList(String.class));
|
||||
}
|
||||
//获取删除的文件列表
|
||||
JSONArray removedList=commit.getJSONArray("removed");
|
||||
if(removedList!=null){
|
||||
syncDocRemovedData(cmsProject,removedList.toJavaList(String.class));
|
||||
JSONArray removedList = commit.getJSONArray("removed");
|
||||
if (removedList != null) {
|
||||
syncDocRemovedData(cmsProject, removedList.toJavaList(String.class));
|
||||
}
|
||||
//获取更新的文件列表
|
||||
JSONArray modifiedList=commit.getJSONArray("modified");
|
||||
if(modifiedList!=null){
|
||||
JSONArray modifiedList = commit.getJSONArray("modified");
|
||||
if (modifiedList != null) {
|
||||
syncDocModifiedData(cmsProject, modifiedList.toJavaList(String.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
logger.error("同步文章时发送异常:{}", e.getMessage());
|
||||
}finally {
|
||||
} finally {
|
||||
//本次同步执行完成后,再弹出该UUID
|
||||
redisService.rightPop(cmsSyncDeptIdKey, 500, TimeUnit.MICROSECONDS);
|
||||
}
|
||||
|
|
@ -469,12 +473,12 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void syncCreateDir(String dirName,EntryDto entry,CmsProject cmsProject,boolean isCreateKeep){
|
||||
public void syncCreateDir(String dirName, EntryDto entry, CmsProject cmsProject, boolean isCreateKeep) {
|
||||
CmsDoc cmsDir = new CmsDoc();
|
||||
cmsDir.setName(dirName);
|
||||
cmsDir.setCreateTime(entry.getCommit().getCreated_at());
|
||||
boolean insertResult;
|
||||
if(isCreateKeep){
|
||||
if (isCreateKeep) {
|
||||
//若该栏目不存在,检查文件夹中是否存在.keep文件
|
||||
JSONObject subEntriesResult = gitLinkRequestHelper.doGet(
|
||||
CmsGitLinkRequestUrl.GET_FILE_SUB_ENTRIES(cmsProject, cmsDir.getName(), CmsConstants.BRANCH_MASTER));
|
||||
|
|
@ -484,14 +488,14 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
|
||||
if (keepEntry != null) {
|
||||
//若存在,则在数据库中创建该栏目
|
||||
insertResult=createCmsDir(cmsDir,cmsProject.getDeptId(),keepEntry);
|
||||
insertResult = createCmsDir(cmsDir, cmsProject.getDeptId(), keepEntry);
|
||||
} else {
|
||||
//若不存在,则在数据库中创建该栏目,同时在仓库的该文件夹下创建.keep文件
|
||||
insertResult = cmsDocService.insertCmsDocDir(cmsProject.getDeptId(), cmsDir.copyToCmsDir());
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
//若不自动创建,则在数据库中创建根据文件名该栏目
|
||||
insertResult=createCmsDir(cmsDir,cmsProject.getDeptId(),entry);
|
||||
insertResult = createCmsDir(cmsDir, cmsProject.getDeptId(), entry);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -500,7 +504,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean createCmsDir(CmsDoc cmsDir,Long deptId,EntryDto entry){
|
||||
private boolean createCmsDir(CmsDoc cmsDir, Long deptId, EntryDto entry) {
|
||||
cmsDir.setIsDir(true);
|
||||
cmsDir.setFilePath(cmsDir.getDirPath());
|
||||
cmsDir.setDeptId(deptId);
|
||||
|
|
@ -678,6 +682,7 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
requestBody);
|
||||
cmsDoc.setAuditPrNumber(result.getString("pull_request_number") + "-" + result.getString("pull_request_id"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsDoc updateCmsDocDatabaseAndUpdateForGitLink(CmsDoc oldCmsDoc, CmsDocDto cmsDocDto, String branchName) {
|
||||
if (oldCmsDoc == null) {
|
||||
|
|
@ -871,27 +876,87 @@ public class CmsAsyncServiceImpl implements ICmsAsyncService {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Async
|
||||
public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir) {
|
||||
public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, String newCmsDirName) {
|
||||
try {
|
||||
remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 1, SecurityConstants.INNER);
|
||||
//创建新栏目
|
||||
String message = String.format("重命名栏目:由[%s]重命名为[%s]", oldCmsDir.getName(), newCmsDir.getName());
|
||||
cmsDocService.createFileByGitLink(newCmsDir, message, "");
|
||||
//在数据库中重命名该栏目,防止后续操作推送的WebHook重复创建栏目
|
||||
cmsDocService.updateCmsCommonDatabase(newCmsDir, CmsConstants.BRANCH_MASTER);
|
||||
//将原栏目中所有文章移动到新栏目中
|
||||
moveCmsDocToNewCmsDir(cmsProject, oldCmsDir.getName(), newCmsDir.getName(), message);
|
||||
//删除旧栏目
|
||||
deleteCmsDocByGitLink(cmsProject, oldCmsDir);
|
||||
JSONObject dirFilesJson = gitLinkRequestHelper.doGet(CmsGitLinkRequestUrl.GET_DIR_SUB_ENTRIES(
|
||||
cmsProject,
|
||||
oldCmsDir.getName(),
|
||||
CmsConstants.BRANCH_MASTER));
|
||||
List<EntryDto> entryDtoList = cmsDocService.getEntriesFromRequestResult(dirFilesJson, cmsProject, false);
|
||||
CountDownLatch countDownLatch = new CountDownLatch(entryDtoList.size());
|
||||
// 异步获取每篇文章内容
|
||||
entryDtoList.forEach(entryDto -> {
|
||||
CustomExecutorFactory.threadPoolExecutor.execute(() -> {
|
||||
try {
|
||||
JSONObject fileSubEntriesResult = gitLinkRequestHelper.doGet(
|
||||
CmsGitLinkRequestUrl.GET_FILE_SUB_ENTRIES(
|
||||
cmsProject,
|
||||
entryDto.getPath(),
|
||||
CmsConstants.BRANCH_MASTER));
|
||||
EntryDto cmsDocEntryDto = EntryDto.getEntryDtoFromJson(fileSubEntriesResult);
|
||||
entryDto.setContent(cmsDocEntryDto.getContent());
|
||||
} finally {
|
||||
countDownLatch.countDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
try {
|
||||
countDownLatch.await();
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("栏目重命名失败(将对应代码库中文章移动至新文件夹失败):{}", e.getMessage());
|
||||
throw new ServiceException("栏目重命名失败");
|
||||
}
|
||||
|
||||
for (EntryDto entryDto : entryDtoList) {
|
||||
JSONObject updateFileBody = new JSONObject();
|
||||
updateFileBody.put("branch", CmsConstants.BRANCH_MASTER);
|
||||
updateFileBody.put("message", "移动文章至新栏目");
|
||||
updateFileBody.put("from_path", entryDto.getPath());
|
||||
String newFilePath = newCmsDirName + "/" + entryDto.getName();
|
||||
updateFileBody.put("filepath", newFilePath);
|
||||
updateFileBody.put("base64_filepath", Base64.contentToBase64(newFilePath));
|
||||
updateFileBody.put("sha", entryDto.getSha());
|
||||
String content = entryDto.getContent();
|
||||
if (content == null) {
|
||||
content = "";
|
||||
}
|
||||
updateFileBody.put("content", content);
|
||||
gitLinkRequestHelper.doPut(CmsGitLinkRequestUrl.UPDATE_FILE(cmsProject), updateFileBody);
|
||||
}
|
||||
CmsDoc newCmsDoc = oldCmsDir.copyToRenameCmsDir(newCmsDirName);
|
||||
//在数据库中重命名该栏目
|
||||
cmsDocService.updateCmsCommonDatabase(newCmsDoc, CmsConstants.BRANCH_MASTER);
|
||||
} catch (Exception e) {
|
||||
logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}]):{}", oldCmsDir.getName(), newCmsDir.getName(), e.getMessage());
|
||||
throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDir.getName() + "])");
|
||||
} finally {
|
||||
remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
|
||||
logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}]):{}", oldCmsDir.getName(), newCmsDirName, e.getMessage());
|
||||
throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDirName + "])");
|
||||
}
|
||||
// finally {
|
||||
// remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
|
||||
// }
|
||||
}
|
||||
|
||||
// @Override
|
||||
// @Async
|
||||
// public void asyncMoveFileToNewDir(CmsProject cmsProject, CmsDoc oldCmsDir, CmsDoc newCmsDir) {
|
||||
// try {
|
||||
// remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 1, SecurityConstants.INNER);
|
||||
// //创建新栏目
|
||||
// String message = String.format("重命名栏目:由[%s]重命名为[%s]", oldCmsDir.getName(), newCmsDir.getName());
|
||||
// cmsDocService.createFileByGitLink(newCmsDir, message, "");
|
||||
// //在数据库中重命名该栏目,防止后续操作推送的WebHook重复创建栏目
|
||||
// cmsDocService.updateCmsCommonDatabase(newCmsDir, CmsConstants.BRANCH_MASTER);
|
||||
// //将原栏目中所有文章移动到新栏目中
|
||||
// moveCmsDocToNewCmsDir(cmsProject, oldCmsDir.getName(), newCmsDir.getName(), message);
|
||||
// //删除旧栏目
|
||||
// deleteCmsDocByGitLink(cmsProject, oldCmsDir);
|
||||
// } catch (Exception e) {
|
||||
// logger.error("重命名栏目失败(原栏目名称[{}],新栏目名称[{}]):{}", oldCmsDir.getName(), newCmsDir.getName(), e.getMessage());
|
||||
// throw new ServiceException("重命名栏目失败(原栏目名称[" + oldCmsDir.getName() + "],新栏目名称[" + newCmsDir.getName() + "])");
|
||||
// } finally {
|
||||
// remoteZoneService.lockCmsByDeptId(cmsProject.getDeptId(), 0, SecurityConstants.INNER);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Async
|
||||
@Override
|
||||
public void pushDocDataSearchEngine(CmsDoc cmsDoc) {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(cmsDoc.getDeptId());
|
||||
|
||||
String branchName = DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus()) ? CmsConstants.BRANCH_MASTER : cmsDoc.getAuditTmpBranchName();
|
||||
String branchName = DocAuditStatus.AUDIT_PASS.getAuditCode().equals(cmsDoc.getAuditStatus()) ? CmsConstants.BRANCH_MASTER : cmsDoc.getAuditTmpBranchName();
|
||||
FileEntryDto fileEntryDto = getFileEntryDto(cmsProject, cmsDoc.getFilePath(), branchName);
|
||||
EntryDto entryDto = fileEntryDto.getEntries();
|
||||
|
||||
|
|
@ -197,20 +197,21 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
@Override
|
||||
public void updateCmsDir(Long id, CmsDirUpdateVo cmsDirUpdateVo) {
|
||||
CmsDoc oldCmsDir = selectCmsDir(id);
|
||||
checkCmsLockStatus(oldCmsDir.getDeptId());
|
||||
//设置栏目排序
|
||||
setCmsSort(cmsDirUpdateVo.getOrder(), oldCmsDir, false, null);
|
||||
oldCmsDir.setHeadImg(cmsDirUpdateVo.getHeadImg());
|
||||
updateCmsCommonDatabase(oldCmsDir, CmsConstants.BRANCH_MASTER);
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(oldCmsDir.getDeptId());
|
||||
CmsDoc newCmsDir = oldCmsDir.copyToRenameCmsDir(cmsDirUpdateVo.getName());
|
||||
String newCmsDirName = cmsDirUpdateVo.getName();
|
||||
|
||||
if (StringUtils.isNotEmpty(newCmsDir.getName()) && !newCmsDir.getName().equals(oldCmsDir.getName())) {
|
||||
CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(newCmsDir.getName(), oldCmsDir.getDeptId());
|
||||
if (StringUtils.isNotEmpty(newCmsDirName) && !newCmsDirName.equals(oldCmsDir.getName())) {
|
||||
CmsDoc cmsDir = cmsDocMapper.selectCmsDocDirByNameAndDeptId(newCmsDirName, oldCmsDir.getDeptId());
|
||||
if (cmsDir != null) {
|
||||
throw new ServiceException("栏目名称已存在,不允许进行重命名(新栏目名称[" + newCmsDir.getName() + "])");
|
||||
}
|
||||
cmsAsyncService.asyncMoveFileToNewDir(cmsProject, oldCmsDir, newCmsDir);
|
||||
throw new ServiceException("栏目名称已存在,不允许进行重命名(新栏目名称[" + newCmsDirName + "])");
|
||||
}
|
||||
// 异步修改栏目名称(将仓库内原文件夹下所有文章移动到新文件夹下)
|
||||
cmsAsyncService.asyncMoveFileToNewDir(cmsProject, oldCmsDir, newCmsDirName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -237,7 +238,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
cmsDocSearchVo.setDirName(cmsDir.getName());
|
||||
cmsDocSearchVo.setDeptId(cmsDir.getDeptId());
|
||||
cmsDocSearchVo.setIsDir(false);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearchVo);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearchVo);
|
||||
List<CompletableFuture<CmsDocDetailDto>> futures = new ArrayList();
|
||||
for (CmsDoc cmsDoc : cmsDocList) {
|
||||
CompletableFuture<CmsDocDetailDto> future = CompletableFuture.supplyAsync(() -> {
|
||||
|
|
@ -283,6 +284,21 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return selectCmsDocListByDatabase(dirId, cmsDocSearchVo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CmsDocBaseDto> selectSetDefaultHeadImgCmsDocList(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
return selectCmsDocListSetDefaultHeadImgByDatabase(dirId, cmsDocSearchVo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<CmsDoc> selectCmsDocAndDirListByDept(Long deptId) {
|
||||
return cmsDocMapper.selectCmsDocAndDirListByDept(deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCmsDocShaByPathAndDeptId(String sha, String filePath, Long deptId) {
|
||||
cmsDocMapper.updateCmsDocShaByPathAndDeptId(sha,filePath,deptId);
|
||||
}
|
||||
|
||||
private List<CmsDocBaseDto> selectCmsDocListByDatabase(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
CmsDoc cmsDocDir = selectCmsDir(dirId);
|
||||
|
||||
|
|
@ -295,6 +311,24 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
return cmsDocList.stream().map(CmsDoc::copyToCmsDocBaseDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置文章默认头图为栏目头图
|
||||
* @param dirId 栏目id
|
||||
* @param cmsDocSearchVo 文章查询条件
|
||||
* @return 文章列表
|
||||
*/
|
||||
private List<CmsDocBaseDto> selectCmsDocListSetDefaultHeadImgByDatabase(Long dirId, CmsDocSearchVo cmsDocSearchVo) {
|
||||
CmsDoc cmsDocDir = selectCmsDir(dirId);
|
||||
|
||||
cmsDocSearchVo.setDeptId(cmsDocDir.getDeptId());
|
||||
cmsDocSearchVo.setDirName(cmsDocDir.getName());
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearchVo);
|
||||
if (cmsDocList == null || cmsDocList.isEmpty()) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
return cmsDocList.stream().map(CmsDoc::copyToCmsDocBaseDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查专区资讯是否处于锁定状态,若处于则抛出异常
|
||||
*
|
||||
|
|
@ -552,6 +586,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
throw new ServiceException("计算字符串Sha出错");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCmsSort(Integer order, CmsDoc oldCmsDoc, boolean isChangeOnDir, String isHomePage) {
|
||||
//调整文章/栏目顺序
|
||||
|
|
@ -697,7 +732,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
Long originCmsDocId = Long.parseLong(oldCmsDoc.getAuditType().split("-")[1]);
|
||||
CmsDoc originCmsDoc = cmsDocMapper.selectCmsDocById(originCmsDocId);
|
||||
deleteTmpBranchIfBranchExist(oldCmsDoc);
|
||||
BeanUtils.copyProperties(originCmsDoc,oldCmsDoc);
|
||||
BeanUtils.copyProperties(originCmsDoc, oldCmsDoc);
|
||||
cmsDocMapper.deleteCmsDocById(id);
|
||||
} else
|
||||
//文章审核类型:create 直接新增文章
|
||||
|
|
@ -724,11 +759,11 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
} else
|
||||
//更新已发布文章
|
||||
if (oldCmsDoc.getAuditStatus().equals(DocAuditStatus.AUDIT_PASS.getAuditCode())) {
|
||||
//1.创建一条auditType="update-原文章id",audit_status为2,其余字段与待更新文章一致的新文章数据
|
||||
newDocWithAudit = insertDocWithAudit(oldCmsDoc,
|
||||
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + id,
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
}
|
||||
//1.创建一条auditType="update-原文章id",audit_status为2,其余字段与待更新文章一致的新文章数据
|
||||
newDocWithAudit = insertDocWithAudit(oldCmsDoc,
|
||||
DocAndZoneOperation.OPERATION_UPDATE.getOperationCode() + "-" + id,
|
||||
DocAuditStatus.TO_BE_AUDIT.getAuditCode());
|
||||
}
|
||||
cmsAsyncService.asyncUpdateBranchAndFileAndCreatePR(newDocWithAudit, cmsDocDto);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -785,7 +820,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
gitLinkRequestHelper.doDelete(CmsGitLinkRequestUrl.DELETE_BRANCH(cmsProject, cmsDoc.getAuditTmpBranchName()));
|
||||
} catch (ServiceException e) {
|
||||
//忽略分支不存在异常
|
||||
if(!"分支不存在!".equals(e.getMessage())) {
|
||||
if (!"分支不存在!".equals(e.getMessage())) {
|
||||
throw new ServiceException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
|
@ -863,6 +898,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
cmsDoc.setIsDir(true);
|
||||
cmsDoc.setFilePath(cmsDoc.getDirPath(cmsDir.getName()));
|
||||
cmsDoc.setDeptId(deptId);
|
||||
cmsDoc.setHeadImg(cmsDir.getHeadImg());
|
||||
cmsDoc.setName(cmsDir.getName());
|
||||
return insertCommonCmsDoc(cmsDoc, "创建栏目:" + cmsDir.getName(), "");
|
||||
}
|
||||
|
|
@ -949,7 +985,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
List<CmsDoc> cmsDocList = cmsDocMapper.selectHotCmsDocList(cmsDocInput);
|
||||
if (cmsDocList != null) {
|
||||
//todo:需检查该文章是否在GitLink中存在
|
||||
return cmsDocList.stream().map(x -> x.copyToHotCmsDocDto()).collect(Collectors.toList());
|
||||
return cmsDocList.stream().map(CmsDoc::copyToHotCmsDocDto).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
|
|
@ -990,7 +1026,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
for (CmsDoc cmsDir : cmsDirList) {
|
||||
CmsDocSearchVo cmsDocSearchVo = new CmsDocSearchVo();
|
||||
cmsDocSearchVo.setIsOpen(isOpen);
|
||||
List<CmsDocBaseDto> cmsDocBaseDtoList = selectCmsDocList(cmsDir.getId(), cmsDocSearchVo);
|
||||
List<CmsDocBaseDto> cmsDocBaseDtoList = selectSetDefaultHeadImgCmsDocList(cmsDir.getId(), cmsDocSearchVo);
|
||||
CmsDocOverviewDto cmsDocOverviewDto = new CmsDocOverviewDto();
|
||||
cmsDocOverviewDto.setId(cmsDir.getId());
|
||||
cmsDocOverviewDto.setName(cmsDir.getName());
|
||||
|
|
@ -1104,7 +1140,7 @@ public class CmsDocServiceImpl implements ICmsDocService {
|
|||
CmsDocSearchVo cmsDocSearch = new CmsDocSearchVo();
|
||||
cmsDocSearch.setDeptId(deptId);
|
||||
cmsDocSearch.setIsHomepage(CmsConstants.TRUE);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocList(cmsDocSearch);
|
||||
List<CmsDoc> cmsDocList = cmsDocMapper.selectCmsDocListSetDefaultHeadImg(cmsDocSearch);
|
||||
List<CmsDocBaseDto> cmsDocBaseDtoList = new ArrayList<>();
|
||||
for (CmsDoc cmsDoc : cmsDocList) {
|
||||
CmsDocBaseDto cmsDocBaseDto = cmsDoc.copyToCmsDocBaseDto();
|
||||
|
|
|
|||
|
|
@ -95,8 +95,12 @@ public class CmsProjectController extends BaseController {
|
|||
@GetMapping("/getProjectByDeptId/{deptId}")
|
||||
public R<String> getProjectByDeptId(
|
||||
@ApiParam(name = "deptId", value = "组织Id") @PathVariable(value = "deptId") Long deptId) {
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptId(deptId);
|
||||
return R.ok(JSONObject.toJSONString(cmsProject));
|
||||
CmsProject cmsProject = cmsProjectService.selectCmsProjectByDeptIdAndNoException(deptId);
|
||||
if (cmsProject == null) {
|
||||
return R.ok(null);
|
||||
} else {
|
||||
return R.ok(JSONObject.toJSONString(cmsProject));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -170,4 +174,16 @@ public class CmsProjectController extends BaseController {
|
|||
public R<Boolean> removeByDeptId(@PathVariable(value = "deptId") Long deptId) {
|
||||
return R.ok(cmsProjectService.deleteCmsProjectByDeptId(deptId) > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化专区对应项目
|
||||
*/
|
||||
@RequiresPermissions("zone:project:add")
|
||||
@ApiOperation("初始化专区对应项目")
|
||||
@Log(title = "初始化专区对应项目", businessType = BusinessType.INSERT)
|
||||
@PostMapping("initCmsProject/dept/{deptId}")
|
||||
public AjaxResult initCmsProject(
|
||||
@ApiParam(name = "deptId", value = "组织Id") @PathVariable(value = "deptId") Long deptId) {
|
||||
return toAjax(cmsProjectService.initZoneCmsProjectByDept(deptId));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,4 +78,8 @@ public interface ICmsProjectService {
|
|||
Boolean updateCmsProjectByDept(SysDept dept);
|
||||
|
||||
boolean operateProtectedBranchByZoneAuditSetting(String userName, String identifier, Long deptId, String operationType);
|
||||
|
||||
boolean initZoneCmsProjectByDept(Long deptId);
|
||||
|
||||
CmsProject selectCmsProjectByDeptIdAndNoException(Long deptId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
package com.microservices.cms.project.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.cms.doc.domain.CmsDir;
|
||||
import com.microservices.cms.doc.domain.CmsDocBaseDto;
|
||||
import com.microservices.cms.doc.domain.CmsDocSearchVo;
|
||||
import com.microservices.cms.doc.domain.*;
|
||||
import com.microservices.cms.doc.service.ICmsAsyncService;
|
||||
import com.microservices.cms.doc.service.ICmsDocService;
|
||||
import com.microservices.cms.project.domain.CmsProject;
|
||||
import com.microservices.cms.project.mapper.CmsProjectMapper;
|
||||
import com.microservices.cms.project.service.ICmsProjectService;
|
||||
import com.microservices.cms.utils.CmsConstants;
|
||||
import com.microservices.cms.utils.CmsGitLinkRequestUrl;
|
||||
import com.microservices.common.core.constant.HttpStatus;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
import com.microservices.common.core.enums.SystemRole;
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.PinYinStringUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.datascope.annotation.DataScope;
|
||||
import com.microservices.common.httpClient.domain.GitLinkRequestUrl;
|
||||
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
|
||||
import com.microservices.system.api.RemoteDeptService;
|
||||
import com.microservices.system.api.RemoteUserService;
|
||||
|
|
@ -23,6 +25,7 @@ import com.microservices.system.api.domain.SysDept;
|
|||
import com.microservices.system.api.domain.SysRole;
|
||||
import com.microservices.system.api.domain.SysUser;
|
||||
import com.microservices.system.api.utils.FeignUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
|
|
@ -37,6 +40,7 @@ import java.util.List;
|
|||
* @author otto
|
||||
* @date 2023-03-27
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class CmsProjectServiceImpl implements ICmsProjectService {
|
||||
@Autowired
|
||||
|
|
@ -228,6 +232,75 @@ public class CmsProjectServiceImpl implements ICmsProjectService {
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean initZoneCmsProjectByDept(Long deptId) {
|
||||
boolean initResult = false;
|
||||
CmsProject cmsProject = cmsProjectMapper.selectCmsProjectByDeptId(deptId);
|
||||
if (cmsProject != null) {
|
||||
JSONObject project = null;
|
||||
try {
|
||||
project = gitLinkRequestHelper.doGet(CmsGitLinkRequestUrl.GET_PROJECT_DETAIL(cmsProject.getUsername(), cmsProject.getIdentifier()));
|
||||
} catch (ServiceException e) {
|
||||
if (!e.getCode().equals(HttpStatus.NOT_FOUND)) {
|
||||
throw new ServiceException(e.getCode(), e.getMessage());
|
||||
}
|
||||
}
|
||||
if (project != null) {
|
||||
throw new ServiceException("专区对应项目已存在,不能重复初始化");
|
||||
} else {
|
||||
Long organizationId = getOrganizationId();
|
||||
// 创建专区对应项目
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("user_id", organizationId);
|
||||
jsonObject.put("name", cmsProject.getName());
|
||||
jsonObject.put("repository_name", cmsProject.getIdentifier());
|
||||
jsonObject.put("description", cmsProject.getDescription());
|
||||
jsonObject.put("private", false);
|
||||
//调用GitLink接口创建项目
|
||||
JSONObject result = gitLinkRequestHelper.doPost(CmsGitLinkRequestUrl.CREATE_PROJECT(), jsonObject);
|
||||
initResult = result != null && cmsProject.getIdentifier().equals(result.getString("identifier"));
|
||||
}
|
||||
} else {
|
||||
Long projectId = insertZoneCmsProjectByDept(deptId);
|
||||
if (projectId != null && projectId > 0) {
|
||||
cmsProject = cmsProjectMapper.selectCmsProjectById(projectId);
|
||||
initResult = true;
|
||||
}
|
||||
}
|
||||
if (initResult) {
|
||||
// 批量创建文章对应代码库文件
|
||||
List<CmsDoc> cmsDocAndDirList = cmsDocService.selectCmsDocAndDirListByDept(deptId);
|
||||
if (cmsDocAndDirList == null || cmsDocAndDirList.isEmpty()) {
|
||||
return initResult;
|
||||
}
|
||||
JSONObject docCommitJson = new JSONObject();
|
||||
docCommitJson.put("branch", CmsConstants.BRANCH_MASTER);
|
||||
docCommitJson.put("message", "初始化专区文章对应代码库文件");
|
||||
JSONArray docFiles = new JSONArray();
|
||||
for (CmsDoc cmsDoc : cmsDocAndDirList) {
|
||||
JSONObject docFile = new JSONObject();
|
||||
docFile.put("action_type", "create");
|
||||
docFile.put("content", "");
|
||||
docFile.put("encoding", "text");
|
||||
docFile.put("file_path", cmsDoc.getFilePath());
|
||||
docFiles.add(docFile);
|
||||
}
|
||||
docCommitJson.put("files", docFiles);
|
||||
JSONObject result = gitLinkRequestHelper.doPost(
|
||||
CmsGitLinkRequestUrl.BATCH_COMMIT(cmsProject.getUsername(), cmsProject.getIdentifier())
|
||||
, docCommitJson);
|
||||
if (result == null) {
|
||||
throw new ServiceException("专区对应项目初始化成功,但专区文章在项目中创建失败");
|
||||
}
|
||||
JSONArray resultContents = result.getJSONArray("contents");
|
||||
for (int i = 0; i < resultContents.size(); i++) {
|
||||
JSONObject contentJson = resultContents.getJSONObject(i);
|
||||
cmsDocService.updateCmsDocShaByPathAndDeptId(contentJson.getString("sha"), contentJson.getString("path"), deptId);
|
||||
}
|
||||
}
|
||||
return initResult;
|
||||
}
|
||||
|
||||
|
||||
private String handleSpecialCharacters(String name) {
|
||||
return StringUtils.replace(name, " ", "-");
|
||||
|
|
@ -242,6 +315,11 @@ public class CmsProjectServiceImpl implements ICmsProjectService {
|
|||
return cmsProject;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CmsProject selectCmsProjectByDeptIdAndNoException(Long deptId) {
|
||||
return cmsProjectMapper.selectCmsProjectByDeptId(deptId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean changeUserRole(Long userId, Long oldDeptId, Long newDeptId, Long oldRoleId, Long newRoleId) {
|
||||
SysUser sysUser = FeignUtils.getReturnData(remoteUserService.getSysUserByUserId(userId, SecurityConstants.INNER));
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package com.microservices.cms.common.service.impl;
|
||||
package com.microservices.cms.service.impl;
|
||||
|
||||
import com.microservices.cms.common.service.ISysUserService;
|
||||
import com.microservices.common.core.constant.SecurityConstants;
|
||||
|
|
|
|||
|
|
@ -148,19 +148,19 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl CREATE_PROTECTED_BRANCHES(String username, String identifier, Map<String,String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||
public static GitLinkRequestUrl CREATE_PROTECTED_BRANCHES(String username, String identifier, Map<String, String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||
String path = buildUri(String.format("/api/%s/%s/protected_branches.json", username, identifier), params);
|
||||
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
||||
return getGitLinkRequestUrl(path);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl UPDATE_PROTECTED_BRANCHES(String username, String identifier, Map<String,String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||
public static GitLinkRequestUrl UPDATE_PROTECTED_BRANCHES(String username, String identifier, Map<String, String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||
String path = buildUri(String.format("/api/%s/%s/protected_branches/master.json", username, identifier), params);
|
||||
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
||||
return getGitLinkRequestUrl(path);
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl DELETE_PROTECTED_BRANCHES(String username, String identifier, Map<String,String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||
public static GitLinkRequestUrl DELETE_PROTECTED_BRANCHES(String username, String identifier, Map<String, String> params, List<String> pushWhitelistUsernames) throws URISyntaxException {
|
||||
String path = buildUri(String.format("/api/%s/%s/protected_branches/master.json", username, identifier), params);
|
||||
path = concatenateParametersAfterUrl(path, "push_whitelist_usernames[]", pushWhitelistUsernames);
|
||||
return getGitLinkRequestUrl(path);
|
||||
|
|
@ -197,4 +197,12 @@ public class CmsGitLinkRequestUrl extends GitLinkRequestUrl {
|
|||
public static String ZONE_DOC_URL(String gitlinkUrl, String zoneKey, Long docId) {
|
||||
return EscapeUtil.removeExtraSlashOfUrl(String.format("%s/zone/%s/newdetail/%d", gitlinkUrl, zoneKey, docId));
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl GET_PROJECT_DETAIL(String username, String identifier) {
|
||||
return getAdminGitLinkRequestUrl(String.format("/api/%s/%s/detail.json", username, identifier));
|
||||
}
|
||||
|
||||
public static GitLinkRequestUrl BATCH_COMMIT(String username, String identifier) {
|
||||
return getAdminGitLinkRequestUrl(String.format("/api/v1/%s/%s/contents/batch.json", username, identifier));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,37 @@
|
|||
package com.microservices.cms.utils;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.threadPool.ThreadPoolExecutorWrap;
|
||||
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* 线程池工厂
|
||||
*
|
||||
* @author OTTO
|
||||
*/
|
||||
public class CustomExecutorFactory {
|
||||
/**
|
||||
* 创建线程池
|
||||
* 存在并发处理的情况,设置核心线程为2,设置有界队列长度为100,最大线程数为10
|
||||
* 当超出队列已满且达到最大线程数时抛出异常
|
||||
* Ncpu=CPU数量
|
||||
* Ucpu=目标CPU的使用率,0<=Ucpu<=1
|
||||
* W/C=任务等待时间与任务计算时间的比率
|
||||
* Nthreads =Ncpu*Ucpu*(1+W/C)
|
||||
*/
|
||||
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutorWrap(
|
||||
5
|
||||
, 10
|
||||
, 10
|
||||
, TimeUnit.SECONDS
|
||||
, new ArrayBlockingQueue<>(100)
|
||||
, Executors.defaultThreadFactory()
|
||||
, (r, executor) -> {
|
||||
throw new ServiceException("目前处理的人太多了,请稍后再试");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9116
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -107,6 +107,50 @@
|
|||
from cms_doc cd
|
||||
</sql>
|
||||
|
||||
<sql id="selectCmsDocAliasSetDefaultHeadImgVo">
|
||||
select cd.id,
|
||||
cd.create_by,
|
||||
cd.create_time,
|
||||
cd.update_by,
|
||||
cd.update_time,
|
||||
cd.name,
|
||||
cd.file_name,
|
||||
cd.file_path,
|
||||
cd.file_sha,
|
||||
cd.file_size,
|
||||
cd.file_url,
|
||||
cd.html_url,
|
||||
cd.visits,
|
||||
cd.sort,
|
||||
cd.publish_time,
|
||||
cd.publish_user,
|
||||
cd.publish_user_image,
|
||||
cd.publish_user_url,
|
||||
cd.publish_user_nickname,
|
||||
cd.summary,
|
||||
-- 处理文章和栏目头图为NULL或空字符串的情况
|
||||
CASE
|
||||
-- 文章头图不为空(非NULL且非空字符串)
|
||||
WHEN cd.head_img IS NOT NULL AND TRIM(cd.head_img) != '' THEN cd.head_img
|
||||
-- 栏目存在且头图不为空
|
||||
WHEN dir.head_img IS NOT NULL AND TRIM(dir.head_img) != '' THEN dir.head_img
|
||||
END AS head_img,
|
||||
cd.dir_name,
|
||||
cd.dept_id,
|
||||
cd.issue_id,
|
||||
cd.is_homepage,
|
||||
cd.editor_type,
|
||||
cd.keywords,
|
||||
cd.is_dir
|
||||
from cms_doc cd
|
||||
left join cms_doc dir on cd.dir_name = dir.name and cd.dept_id = dir.dept_id
|
||||
</sql>
|
||||
|
||||
<select id="selectCmsDocAndDirListByDept" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where dept_id=#{deptId}
|
||||
</select>
|
||||
|
||||
<select id="selectCmsDocList" parameterType="com.microservices.cms.doc.domain.CmsDocSearchVo"
|
||||
resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
|
|
@ -150,13 +194,13 @@
|
|||
where file_path = #{filePath} and dept_id = #{deptId} and is_dir = 0
|
||||
</select>
|
||||
<select id="selectHotCmsDocList" parameterType="com.microservices.cms.doc.domain.CmsDoc" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
<include refid="selectListWhere"/>
|
||||
<include refid="selectCmsDocAliasSetDefaultHeadImgVo"/>
|
||||
<include refid="selectListWhereAlias"/>
|
||||
ORDER BY
|
||||
visits DESC,
|
||||
sort DESC,
|
||||
update_time DESC,
|
||||
create_time DESC
|
||||
cd.visits DESC,
|
||||
cd.sort DESC,
|
||||
cd.update_time DESC,
|
||||
cd.create_time DESC
|
||||
|
||||
</select>
|
||||
<select id="selectCmsDocCount" resultType="java.lang.Integer">
|
||||
|
|
@ -180,6 +224,23 @@
|
|||
</where>
|
||||
</sql>
|
||||
|
||||
<sql id="selectListWhereAlias">
|
||||
<where>
|
||||
<if test="name != null and name != ''">and cd.name like concat('%', #{name}, '%')</if>
|
||||
<if test="keywords != null and keywords != ''">and cd.keywords like concat('%', #{keywords}, '%')</if>
|
||||
<if test="fileName != null and fileName != ''">and cd.file_name like concat('%', #{fileName}, '%')</if>
|
||||
<if test="filePath != null and filePath != ''">and cd.file_path = #{filePath}</if>
|
||||
<if test="publishTime != null ">and cd.publish_time = #{publishTime}</if>
|
||||
<if test="isDir != null ">and cd.is_dir = #{isDir}</if>
|
||||
<if test="dirName != null ">and cd.dir_name = #{dirName}</if>
|
||||
<if test="deptId != null ">and cd.dept_id = #{deptId}</if>
|
||||
<if test="isHomepage != null ">and cd.is_homepage = #{isHomepage}</if>
|
||||
<if test="auditStatus != null and auditStatus != '-1' ">and cd.audit_status = #{auditStatus}</if>
|
||||
<if test="auditStatus == null ">and cd.audit_status = '1'</if>
|
||||
<if test="createBy != null and createBy != '' ">and cd.create_by = #{createBy}</if>
|
||||
</where>
|
||||
</sql>
|
||||
|
||||
<select id="selectCmsDocDirByDeptIdAndInName" resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocVo"/>
|
||||
where dept_id = #{deptId} and is_dir = 1
|
||||
|
|
@ -283,6 +344,15 @@
|
|||
from cms_doc
|
||||
where dept_id = #{deptId};
|
||||
</select>
|
||||
<select id="selectCmsDocListSetDefaultHeadImg" parameterType="com.microservices.cms.doc.domain.CmsDocSearchVo"
|
||||
resultMap="CmsDocResult">
|
||||
<include refid="selectCmsDocAliasSetDefaultHeadImgVo"/>
|
||||
<include refid="selectListWhereAlias"/>
|
||||
ORDER BY
|
||||
cd.sort DESC,
|
||||
cd.update_time DESC,
|
||||
cd.create_time DESC
|
||||
</select>
|
||||
|
||||
<insert id="insertCmsDoc" parameterType="com.microservices.cms.doc.domain.CmsDoc" useGeneratedKeys="true"
|
||||
keyProperty="id">
|
||||
|
|
@ -405,6 +475,12 @@
|
|||
and dept_id = #{deptId}
|
||||
and is_dir = #{isDir};
|
||||
</update>
|
||||
<update id="updateCmsDocShaByPathAndDeptId">
|
||||
update cms_doc
|
||||
set file_sha=#{sha}
|
||||
where file_path=#{filePath}
|
||||
and dept_id=#{deptId}
|
||||
</update>
|
||||
|
||||
<delete id="deleteCmsDocById" parameterType="Long">
|
||||
delete
|
||||
|
|
|
|||
|
|
@ -87,10 +87,18 @@
|
|||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-swagger</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-log</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-core</artifactId>
|
||||
|
|
@ -125,7 +133,7 @@
|
|||
<dependency>
|
||||
<groupId>com.hankcs</groupId>
|
||||
<artifactId>hanlp</artifactId>
|
||||
<version>portable-1.8.4</version>
|
||||
<version>portable-1.3.4</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ public class SchoolEnterpriseAchievements extends BaseEntity {
|
|||
)
|
||||
private String achievementCurStatus;
|
||||
//团队名称
|
||||
@Excel(name = "成果团队名称")
|
||||
private String teamName;
|
||||
|
||||
private List<AchievementTeam> teamList;
|
||||
|
|
|
|||
|
|
@ -172,8 +172,7 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
|||
schoolEnterpriseAchievement.setCreateTime(new Date());
|
||||
schoolEnterpriseAchievement.setUpdateBy(operName);
|
||||
schoolEnterpriseAchievement.setUpdateTime(new Date());
|
||||
schoolEnterpriseAchievement.setStatus("0");
|
||||
schoolEnterpriseAchievement.setAchievementStatus(0);
|
||||
schoolEnterpriseAchievement.setStatus("2");
|
||||
schoolEnterpriseAchievementsMapper.insertSchoolEnterpriseAchievements(schoolEnterpriseAchievement);
|
||||
successNum++;
|
||||
successMsg.append("<br/>").append(successNum).append("、成果 ").append(schoolEnterpriseAchievement.getAchievementName()).append(" 导入成功");
|
||||
|
|
@ -223,6 +222,7 @@ public class SchoolEnterpriseAchievementsServiceImpl implements ISchoolEnterpris
|
|||
private String handleAchievementImage(SchoolEnterpriseAchievements achievement, Map<String, MultipartFile> imageMap) {
|
||||
String imageCellKey = achievement.getImages();
|
||||
if (StringUtils.isEmpty(imageCellKey) || !imageMap.containsKey(imageCellKey)) {
|
||||
achievement.setImages("[]");
|
||||
return "无图片,跳过处理";
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9119
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -473,7 +473,7 @@
|
|||
from (
|
||||
(select count(1) as "auditSum"
|
||||
from memos
|
||||
where destroy_status is null and hidden = 0 and published_at is not null) a,
|
||||
where destroy_status is null and hidden = 0 and published_at is not null AND root_id IS NULL) a,
|
||||
(select count(1) as "allSum" from memos) b,
|
||||
(select count(1) as "currentYearSum"
|
||||
from memos
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9198
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9111
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Tomcat
|
||||
server:
|
||||
port: 9113
|
||||
port: 8080
|
||||
|
||||
# Spring
|
||||
spring:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,127 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-modules</artifactId>
|
||||
<version>3.6.2</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>microservices-modules-mon</artifactId>
|
||||
|
||||
<description>
|
||||
microservices-modules-mon运维监控模块
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Nacos Config -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringCloud Alibaba Sentinel -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- SpringBoot Actuator -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-actuator</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Swagger UI -->
|
||||
<dependency>
|
||||
<groupId>io.springfox</groupId>
|
||||
<artifactId>springfox-swagger-ui</artifactId>
|
||||
<version>${swagger.fox.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Mysql Connector -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common Async -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-async</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common DataSource -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-datasource</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common DataScope -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-datascope</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common Log -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-log</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Microservices Common Swagger -->
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-swagger</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microservices</groupId>
|
||||
<artifactId>microservices-common-httpClient</artifactId>
|
||||
<version>3.6.2</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.microservices.mon;
|
||||
|
||||
import com.microservices.common.security.annotation.EnableCustomConfig;
|
||||
import com.microservices.common.security.annotation.EnableRyFeignClients;
|
||||
import com.microservices.common.swagger.annotation.EnableCustomSwagger2;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
|
||||
/**
|
||||
* 运维监控模块
|
||||
*
|
||||
* @author otto
|
||||
*/
|
||||
@EnableCustomConfig
|
||||
@EnableCustomSwagger2
|
||||
@EnableRyFeignClients
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
public class MicroservicesMonApplication {
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MicroservicesMonApplication.class, args);
|
||||
System.out.println("(♥◠‿◠)ノ゙ 运维监控模块启动成功 ლ(´ڡ`ლ)゙ \n");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.microservices.mon.k8s.controller;
|
||||
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.mon.k8s.domain.*;
|
||||
import com.microservices.mon.k8s.service.IK8sDashboardService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("dashboard")
|
||||
@Api(tags = "微服务大屏")
|
||||
@RefreshScope
|
||||
public class DashboardController extends BaseController {
|
||||
@Autowired
|
||||
private IK8sDashboardService k8sDashboardService;
|
||||
|
||||
/**
|
||||
* 获取命名空间列表
|
||||
*/
|
||||
@ApiOperation(value = "获取命名空间列表")
|
||||
@GetMapping("/namespace/list")
|
||||
public GenericsTableDataInfo<K8sNamespace> namespaceList(@RequestParam(value = "search", required = false) @ApiParam(value = "根据应用名称查找") String search) {
|
||||
return new GenericsTableDataInfo<>(k8sDashboardService.getNamespaceDetailList(true,search));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取集群节点列表")
|
||||
@GetMapping("/cluster/Nodelist")
|
||||
public GenericsTableDataInfo<K8sClusterNode> clusterNodeList() {
|
||||
return new GenericsTableDataInfo<>(k8sDashboardService.getClusterNodeList());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取应用容器Ip列表")
|
||||
@GetMapping("/application/{kind}/{namespace}/{applicationName}/podIdList")
|
||||
public GenericsTableDataInfo<String> applicationPodIdList(@PathVariable("kind") String kind, @PathVariable("namespace") String namespace, @PathVariable("applicationName") String applicationName) {
|
||||
return new GenericsTableDataInfo<>(k8sDashboardService.getApplicationPodIdList(kind, namespace, applicationName));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取集群状态数据")
|
||||
@GetMapping("/cluster/status")
|
||||
public GenericsAjaxResult<K8sClusterStatus> clusterStatus() {
|
||||
return GenericsAjaxResult.success(k8sDashboardService.getClusterStatus());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "集群每秒请求率(QPS)")
|
||||
@GetMapping("/cluster/qps")
|
||||
public GenericsTableDataInfo<MetricCommonData> clusterQps() {
|
||||
return new GenericsTableDataInfo<>(k8sDashboardService.getClusterQps());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "最近24小时应用接口请求次数")
|
||||
@GetMapping("/cluster/applicationRequestCount")
|
||||
public GenericsTableDataInfo<ApplicationRequestCountData> applicationRequestCount() {
|
||||
return new GenericsTableDataInfo<>(k8sDashboardService.getApplicationRequestCount());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取Pod容器状态")
|
||||
@GetMapping("/cluster/podContainerStatus/{podName}")
|
||||
public GenericsAjaxResult<K8sPodContainerStatus> podContainerStatus(@PathVariable("podName") String podName) {
|
||||
return GenericsAjaxResult.success(k8sDashboardService.getPodContainerStatus(podName));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取服务器节点状态")
|
||||
@GetMapping("/cluster/nodeStatus/{nodeIp}")
|
||||
public GenericsAjaxResult<K8sNodeStatus> nodeStatus(@PathVariable("nodeIp") String nodeIp) {
|
||||
return GenericsAjaxResult.success(k8sDashboardService.getNodeStatus(nodeIp));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取微服务应用功能列表")
|
||||
@GetMapping("/applicationFunction/{kind}/{namespace}/{applicationName}")
|
||||
public GenericsTableDataInfo<ApplicationFunction> applicationFunction(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestParam("podIpList") @ApiParam(value = "Pod Ip列表(使用逗号分割的ip列表字符串)") String podIpList) {
|
||||
return new GenericsTableDataInfo<>(k8sDashboardService.getApplicationFunction(kind, namespace, applicationName, podIpList));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
package com.microservices.mon.k8s.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.utils.PageUtils;
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.mon.k8s.domain.*;
|
||||
import com.microservices.mon.k8s.domain.vo.ApplicationEnvTypeVo;
|
||||
import com.microservices.mon.k8s.domain.vo.ApplicationTypeVo;
|
||||
import com.microservices.mon.k8s.domain.vo.CommonTypeVo;
|
||||
import com.microservices.mon.k8s.service.IMicroManagementService;
|
||||
import io.swagger.annotations.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("micro")
|
||||
@Api(tags = "微服务管理")
|
||||
@RefreshScope
|
||||
public class MicroManagementController extends BaseController {
|
||||
@Autowired
|
||||
private IMicroManagementService microManagementService;
|
||||
|
||||
@ApiOperation(value = "获取可视化面板容器列表")
|
||||
@GetMapping("/pod/list")
|
||||
public GenericsTableDataInfo<K8sApplicationPod> podList() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getPodList());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取微服务运行状态监控数据")
|
||||
@GetMapping("/pod/status/{podName}")
|
||||
public GenericsAjaxResult<K8sPodContainerMetricOverview> podStatus(@PathVariable("podName") String podName,
|
||||
@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return GenericsAjaxResult.success(microManagementService.getPodStatus(podName, step));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取微服务应用详情")
|
||||
@GetMapping("/application/{kind}/{namespace}/{applicationName}/detail")
|
||||
public GenericsAjaxResult<K8sApplication> applicationDetail(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName) {
|
||||
return GenericsAjaxResult.success(microManagementService.getApplicationDetail(kind, namespace, applicationName));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除POD容器")
|
||||
@DeleteMapping("/pod/{namespace}/{podName}")
|
||||
public AjaxResult applicationDetail(@PathVariable("namespace") String namespace,
|
||||
@PathVariable("podName") String podName,
|
||||
@RequestParam(value = "isForce", required = false) @ApiParam(value = "是否强制删除") Boolean isForce) {
|
||||
return toAjax(microManagementService.deletePod(namespace, podName, isForce));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "操作应用")
|
||||
@PutMapping("/application/{kind}/{namespace}/{applicationName}/operate/{operationKey}")
|
||||
public AjaxResult operateApplication(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@PathVariable("operationKey") String operationKey) {
|
||||
return toAjax(microManagementService.operateApplication(kind, namespace, applicationName, operationKey));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取应用类型")
|
||||
@GetMapping("/applicationType")
|
||||
public GenericsTableDataInfo<ApplicationTypeVo> applicationType() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getApplicationTypeList());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "创建应用")
|
||||
@PostMapping("/application/{kind}")
|
||||
public AjaxResult createApplication(@PathVariable("kind") String kind,
|
||||
@RequestBody String yamlContent) {
|
||||
return AjaxResult.success(microManagementService.createApplication(kind, yamlContent));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取应用Yaml文件")
|
||||
@GetMapping(value = "/application/{kind}/{namespace}/{applicationName}/yamlFile", produces = "application/yaml")
|
||||
public JSONObject getApplicationYamlFile(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName) {
|
||||
return microManagementService.getApplicationYamlFile(kind, namespace, applicationName);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "编辑应用Yaml文件")
|
||||
@PutMapping("/application/{kind}/{namespace}/{applicationName}")
|
||||
public AjaxResult editApplication(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestBody String yamlContent) {
|
||||
return toAjax(microManagementService.editApplication(kind, namespace, applicationName, yamlContent));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "删除应用")
|
||||
@DeleteMapping("/application/{kind}/{namespace}/{applicationName}")
|
||||
public AjaxResult deleteApplication(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName) {
|
||||
return toAjax(microManagementService.deleteApplication(kind, namespace, applicationName));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取应用环境变量")
|
||||
@GetMapping(value = "/application/{kind}/{namespace}/{applicationName}/env")
|
||||
public GenericsTableDataInfo<K8sApplicationEnv> getApplicationEnv(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName) {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getApplicationEnv(kind, namespace, applicationName));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取应用环境变量相关可选参数")
|
||||
@GetMapping(value = "/application/{namespace}/envOptionalParameters")
|
||||
public GenericsTableDataInfo<K8sApplicationEnvOptionalParameter> getEnvOptionalParameters(@PathVariable("namespace") String namespace) {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getEnvOptionalParameters(namespace));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "更新应用环境变量")
|
||||
@PutMapping("/application/{kind}/{namespace}/{applicationName}/env")
|
||||
public AjaxResult updateApplicationEnv(@PathVariable("kind") String kind,
|
||||
@PathVariable("namespace") String namespace,
|
||||
@PathVariable("applicationName") String applicationName,
|
||||
@RequestBody List<K8sApplicationEnv> k8sApplicationEnvList) {
|
||||
return toAjax(microManagementService.updateApplicationEnv(kind, namespace, applicationName, k8sApplicationEnvList));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取应用环境变量类型")
|
||||
@GetMapping(value = "/application/envTypes")
|
||||
public GenericsTableDataInfo<ApplicationEnvTypeVo> getEnvTypes() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getEnvTypes());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取网关路由配置")
|
||||
@GetMapping(value = "/gateway/routeConfig")
|
||||
public GenericsTableDataInfo<GatewayRouteConfig> getGatewayRouteConfig() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getGatewayRouteConfig());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "更新网关路由配置")
|
||||
@PutMapping(value = "/gateway/routeConfig")
|
||||
public AjaxResult updateGatewayRouteConfig(@RequestBody List<GatewayRouteConfig> gatewayRouteConfigList) {
|
||||
return toAjax(microManagementService.updateGatewayRouteConfig(gatewayRouteConfigList));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取网关安全认证配置")
|
||||
@GetMapping(value = "/gateway/safetyConfig")
|
||||
public GenericsAjaxResult<GatewaySafetyConfig> getGatewaySafetyConfig() {
|
||||
return GenericsAjaxResult.success(microManagementService.getGatewaySafetyConfig());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "更新网关安全认证配置")
|
||||
@PutMapping(value = "/gateway/safetyConfig")
|
||||
public AjaxResult updateGatewaySafetyConfig(@RequestBody GatewaySafetyConfig gatewaySafetyConfig) {
|
||||
return toAjax(microManagementService.updateGatewaySafetyConfig(gatewaySafetyConfig));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取网关白名单配置")
|
||||
@GetMapping(value = "/gateway/whitelistConfig")
|
||||
public GenericsAjaxResult<GatewayWhitelistConfig> getGatewayWhitelistConfig() {
|
||||
return GenericsAjaxResult.success(microManagementService.getGatewayWhitelistConfig());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "更新网关白名单配置")
|
||||
@PutMapping(value = "/gateway/whitelistConfig")
|
||||
public AjaxResult updateGatewayWhitelistConfig(@RequestBody GatewayWhitelistConfig gatewayWhitelistConfig) {
|
||||
return toAjax(microManagementService.updateGatewayWhitelistConfig(gatewayWhitelistConfig));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取存在网关异常处理记录的日期列表")
|
||||
@GetMapping(value = "/gateway/exceptionHandingDateList")
|
||||
public GenericsTableDataInfo<String> getExceptionHandingDateList() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getExceptionHandingDateList());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取网关异常处理记录")
|
||||
@GetMapping(value = "/gateway/exceptionHandingRecordList")
|
||||
public GenericsTableDataInfo<String> getExceptionHandingRecordList(@RequestParam(value = "date", required = false) @ApiParam(value = "查看日期") String date) {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getExceptionHandingRecordList(date));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取网关限流跳转参数")
|
||||
@GetMapping(value = "/gateway/flowLimitingPara")
|
||||
public GenericsAjaxResult<JSONObject> getGatewayFlowLimitingPara() {
|
||||
return GenericsAjaxResult.success(microManagementService.getGatewayFlowLimitingPara());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取链路追踪应用列表")
|
||||
@GetMapping(value = "/application/linkTrackingList")
|
||||
public GenericsTableDataInfo<LinkTrackingApplication> getLinkTrackingList(@RequestParam(value = "applicationName", required = false) @ApiParam(value = "应用名称") String applicationName) {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getLinkTrackingList(applicationName));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取K8S事件关键活动操作列表")
|
||||
@GetMapping(value = "/k8sEvent/keyActivitiesOperationList")
|
||||
public GenericsTableDataInfo<CommonTypeVo> getKeyActivitiesOperationList() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getK8SEventReasonList("Normal"));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取K8S事件关键活动列表")
|
||||
@GetMapping(value = "/k8sEvent/keyActivitiesList")
|
||||
public GenericsTableDataInfo<K8SEvent> getKeyActivitiesList(@RequestParam(value = "reason", required = false) @ApiParam(value = "操作类型") String reason,
|
||||
@RequestParam(value = "startTime", required = false) @ApiParam(value = "开始时间") Date startTime,
|
||||
@RequestParam(value = "endTime", required = false) @ApiParam(value = "结束时间") Date endTime,
|
||||
@RequestParam(value = "isAscOrderByOccurredTime", required = false) @ApiParam(value = "是否根据发生时间升序排序(默认根据发生时间降序排序)") Boolean isAscOrderByOccurredTime,
|
||||
@RequestParam(value = "pageNum", required = false) @ApiParam(value = "当前记录起始索引") Integer pageNum,
|
||||
@RequestParam(value = "pageSize", required = false) @ApiParam(value = "每页显示记录数") Integer pageSize) {
|
||||
return microManagementService.getK8SEventList("Normal", reason, startTime, endTime, isAscOrderByOccurredTime, pageNum, pageSize);
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取K8S事异常结束事件原因列表")
|
||||
@GetMapping(value = "/k8sEvent/exceptionEndReasonList")
|
||||
public GenericsTableDataInfo<CommonTypeVo> getExceptionEndReasonList() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getK8SEventReasonList("Warning"));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取K8S事件异常结束事件列表")
|
||||
@GetMapping(value = "/k8sEvent/exceptionEndList")
|
||||
public GenericsTableDataInfo<K8SEvent> getExceptionEndListList(@RequestParam(value = "reason", required = false) @ApiParam(value = "操作类型") String reason,
|
||||
@RequestParam(value = "startTime", required = false) @ApiParam(value = "开始时间") Date startTime,
|
||||
@RequestParam(value = "endTime", required = false) @ApiParam(value = "结束时间") Date endTime,
|
||||
@RequestParam(value = "isAscOrderByOccurredTime", required = false) @ApiParam(value = "是否根据发生时间升序排序(默认根据发生时间降序排序)") Boolean isAscOrderByOccurredTime,
|
||||
@RequestParam(value = "pageNum", required = false) @ApiParam(value = "当前记录起始索引") Integer pageNum,
|
||||
@RequestParam(value = "pageSize", required = false) @ApiParam(value = "每页显示记录数") Integer pageSize) {
|
||||
return microManagementService.getK8SEventList("Warning", reason, startTime, endTime, isAscOrderByOccurredTime, pageNum, pageSize);
|
||||
}
|
||||
|
||||
|
||||
@ApiOperation(value = "获取K8S资源对象列表")
|
||||
@GetMapping(value = "/k8sEvent/resourceObjectList")
|
||||
public GenericsTableDataInfo<CommonTypeVo> getResourceObjectList() {
|
||||
return new GenericsTableDataInfo<>(microManagementService.getResourceObjectList());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取K8S资源占用列表")
|
||||
@GetMapping(value = "/k8sEvent/resourceUsageList")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "pageNum", value = "当前记录起始索引", paramType = "query", dataType = "Integer"),
|
||||
@ApiImplicitParam(name = "pageSize", value = "每页显示记录数", paramType = "query", dataType = "Integer")
|
||||
})
|
||||
public GenericsTableDataInfo<K8SResourceUsage> getResourceUsageList(@RequestParam(value = "searchResourceObject", required = false) @ApiParam(value = "资源对象") String searchResourceObject,
|
||||
@RequestParam(value = "startTime", required = false) @ApiParam(value = "开始时间") Date startTime,
|
||||
@RequestParam(value = "endTime", required = false) @ApiParam(value = "结束时间") Date endTime) {
|
||||
return getAllGenericsDataTableToPage(microManagementService.getResourceUsageList(searchResourceObject, startTime, endTime));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.microservices.mon.k8s.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.web.controller.BaseController;
|
||||
import com.microservices.common.core.web.domain.AjaxResult;
|
||||
import com.microservices.common.core.web.domain.GenericsAjaxResult;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import com.microservices.mon.k8s.domain.*;
|
||||
import com.microservices.mon.k8s.domain.vo.ApplicationEnvTypeVo;
|
||||
import com.microservices.mon.k8s.domain.vo.ApplicationTypeVo;
|
||||
import com.microservices.mon.k8s.service.IMicroManagementService;
|
||||
import com.microservices.mon.k8s.service.IMicroStatusService;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("microStatus")
|
||||
@Api(tags = "微服务状态监控")
|
||||
@RefreshScope
|
||||
public class MicroStatusController extends BaseController {
|
||||
@Autowired
|
||||
private IMicroStatusService microStatusService;
|
||||
|
||||
@ApiOperation(value = "获取容器启停状态")
|
||||
@GetMapping("/podStartStopStatus")
|
||||
public GenericsAjaxResult<K8sPodStartStopStatus> getPodStartStopStatus() {
|
||||
return GenericsAjaxResult.success(microStatusService.getPodStartStopStatus());
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取容器CPU使用率")
|
||||
@GetMapping("/podCpuUsage")
|
||||
public GenericsTableDataInfo<K8sPodContainerMetric> getPodCpuUsage(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return new GenericsTableDataInfo<>(microStatusService.getPodCpuUsage(step));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取容器内存使用情况")
|
||||
@GetMapping("/podMemoryUsage")
|
||||
public GenericsTableDataInfo<K8sPodContainerMetric> getPodMemoryUsage(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return new GenericsTableDataInfo<>(microStatusService.getPodMemoryUsage(step));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取容器硬盘读取情况")
|
||||
@GetMapping("/podDiskReads")
|
||||
public GenericsTableDataInfo<K8sPodContainerMetric> getPodDiskReads(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return new GenericsTableDataInfo<>(microStatusService.getPodDiskReads(step));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取容器硬盘写入情况")
|
||||
@GetMapping("/podDiskWrites")
|
||||
public GenericsTableDataInfo<K8sPodContainerMetric> getPodDiskWrites(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return new GenericsTableDataInfo<>(microStatusService.getPodDiskWrites(step));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取容器网络接收情况")
|
||||
@GetMapping("/podNetworkReception")
|
||||
public GenericsTableDataInfo<K8sPodContainerMetric> getPodNetworkReception(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return new GenericsTableDataInfo<>(microStatusService.getPodNetworkReception(step));
|
||||
}
|
||||
|
||||
@ApiOperation(value = "获取容器网络发送情况")
|
||||
@GetMapping("/podNetworkTransmission")
|
||||
public GenericsTableDataInfo<K8sPodContainerMetric> getPodNetworkTransmission(@RequestParam(value = "step", required = false) @ApiParam(value = "统计频率") Long step) {
|
||||
return new GenericsTableDataInfo<>(microStatusService.getPodNetworkTransmission(step));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author OTTO
|
||||
*/
|
||||
@Getter
|
||||
public enum ApplicationEnvType {
|
||||
|
||||
KEY_VALUE_PAIR("keyValuePair", "键值对"),
|
||||
RESOURCE("resource", "资源字段"),
|
||||
CONFIG_MAP_KEY("configMapKey", "ConfigMap键"),
|
||||
SECRET_KEY("secretKey", "Secret键"),
|
||||
POD_FIELD("podField", "容器字段"),
|
||||
SECRET("secret", "Secret整体"),
|
||||
CONFIGMAP("configMap", "ConfigMap整体");
|
||||
|
||||
private final String key;
|
||||
private final String alias;
|
||||
|
||||
ApplicationEnvType(String key, String alias) {
|
||||
this.key = key;
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public static ApplicationEnvType getApplicationEnvTypeByKey(String type) {
|
||||
for (ApplicationEnvType applicationEnvType : ApplicationEnvType.values()) {
|
||||
if (StringUtils.equals(applicationEnvType.getKey(), type)) {
|
||||
return applicationEnvType;
|
||||
}
|
||||
}
|
||||
throw new ServiceException("该应用环境变量类型不存在(环境变量类型[%s])", type);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ApiModel("应用功能")
|
||||
public class ApplicationFunction {
|
||||
@ApiModelProperty(value = "应用功能标识")
|
||||
private String key;
|
||||
@ApiModelProperty(value = "应用功能名称")
|
||||
private String name;
|
||||
@ApiModelProperty(value = "应用功能访问所需参数")
|
||||
private JSONObject variables;
|
||||
|
||||
public void setKeyAndName(ApplicationFunctionType applicationFunctionType) {
|
||||
this.key = applicationFunctionType.getKey();
|
||||
this.name = applicationFunctionType.getName();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author OTTO
|
||||
*/
|
||||
@Getter
|
||||
public enum ApplicationFunctionType {
|
||||
LINK_TRACKING("LinkTracking", "链路追踪", "mon-skywalking-key"),
|
||||
FLOW_CONTROL("FlowControl", "流量控制", "mon-sentinel-key"),
|
||||
CONFIGURATION_MANAGEMENT("ConfigurationManagement", "配置管理", ""),
|
||||
REGISTRATION_CENTER("RegistrationCenter", "注册中心", "mon-nacos-key"),
|
||||
GATEWAY_MANAGEMENT("GatewayManagement", "网关管理", "mon-gateway-key"),
|
||||
START_AND_STOP_MANAGEMENT("StartAndStopManagement", "启停管理", "");
|
||||
private final String key;
|
||||
private final String name;
|
||||
private final String k8sLabel;
|
||||
|
||||
ApplicationFunctionType(String key, String name, String k8sLabel) {
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.k8sLabel = k8sLabel;
|
||||
}
|
||||
|
||||
public static ApplicationFunctionType getByLabelsKey(String k8sLabel) {
|
||||
if (StringUtils.isNotEmpty(k8sLabel)) {
|
||||
for (ApplicationFunctionType type : ApplicationFunctionType.values()) {
|
||||
if (type.getK8sLabel().equals(k8sLabel)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@ApiModel("应用请求次数对象")
|
||||
public class ApplicationRequestCountData {
|
||||
|
||||
@ApiModelProperty(value = "序号")
|
||||
private Integer number;
|
||||
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String applicationAlias;
|
||||
|
||||
@ApiModelProperty(value = "请求次数")
|
||||
private Long requestCount;
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.mon.k8s.domain.vo.RancherApplicationVo;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author OTTO
|
||||
*/
|
||||
@Getter
|
||||
public enum ApplicationStartAndStopType {
|
||||
START("start", "启动", false),
|
||||
STOP("stop", "停止", false),
|
||||
FORCE_STOP("forceStop", "强制停止", false),
|
||||
RESTART("restart", "重启", true),
|
||||
PAUSED("paused", "暂停", true),
|
||||
RESUME("resume", "恢复", true);
|
||||
private final String key;
|
||||
private final String name;
|
||||
private final Boolean isDaemonSetOperation;
|
||||
|
||||
ApplicationStartAndStopType(String key, String name, Boolean isDaemonSetOperation) {
|
||||
this.key = key;
|
||||
this.name = name;
|
||||
this.isDaemonSetOperation = isDaemonSetOperation;
|
||||
}
|
||||
|
||||
public static JSONArray getOperationList(String kind, K8sApplication k8sApplication) {
|
||||
JSONArray jsonArray = new JSONArray();
|
||||
if (k8sApplication == null) {
|
||||
return jsonArray;
|
||||
}
|
||||
for (ApplicationStartAndStopType value : values()) {
|
||||
if ("DaemonSet".equals(kind) && !value.isDaemonSetOperation) {
|
||||
continue;
|
||||
}
|
||||
boolean shouldAdd = false;
|
||||
|
||||
switch (value) {
|
||||
case START:
|
||||
if (k8sApplication.getReplicas() == null || k8sApplication.getReplicas() == 0) {
|
||||
shouldAdd = true;
|
||||
}
|
||||
break;
|
||||
case STOP:
|
||||
case FORCE_STOP:
|
||||
case RESTART:
|
||||
if (k8sApplication.getReplicas() != null && k8sApplication.getReplicas() > 0) {
|
||||
shouldAdd = true;
|
||||
}
|
||||
break;
|
||||
case PAUSED:
|
||||
if (!k8sApplication.getPaused()) {
|
||||
shouldAdd = true;
|
||||
}
|
||||
break;
|
||||
case RESUME:
|
||||
if (k8sApplication.getPaused()) {
|
||||
shouldAdd = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (shouldAdd) {
|
||||
JSONObject jsonObject = new JSONObject();
|
||||
jsonObject.put("operationKey", value.getKey());
|
||||
jsonObject.put("operationName", value.getName());
|
||||
jsonArray.add(jsonObject);
|
||||
}
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
|
||||
public static boolean containsKey(String operationKey) {
|
||||
for (ApplicationStartAndStopType value : values()) {
|
||||
if (StringUtils.equals(value.getKey(), operationKey)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ApplicationStartAndStopType getByKey(String operationKey) {
|
||||
for (ApplicationStartAndStopType value : values()) {
|
||||
if (StringUtils.equals(value.getKey(), operationKey)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author OTTO
|
||||
*/
|
||||
@Getter
|
||||
public enum ApplicationType {
|
||||
DAEMON_SET("DaemonSet", "apps.daemonsets", "确保每个节点(或指定节点)上都运行一个容器副本", "daemonsets"),
|
||||
DEPLOYMENT("Deployment", "apps.deployments", "管理无状态应用的容器副本,支持声明式更新和回滚", "deployments"),
|
||||
STATEFUL_SET("StatefulSet", "apps.statefulsets", "管理有状态应用,为容器提供稳定的标识和持久化存储", "statefulsets");
|
||||
private final String key;
|
||||
private final String fullName;
|
||||
private final String description;
|
||||
private final String name;
|
||||
|
||||
ApplicationType(String key, String fullName, String description, String name) {
|
||||
this.key = key;
|
||||
this.fullName = fullName;
|
||||
this.description = description;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public static ApplicationType getApplicationTypeByKey(String key) {
|
||||
for (ApplicationType value : ApplicationType.values()) {
|
||||
if (StringUtils.equalsIgnoreCase(value.getKey(), key)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
throw new ServiceException("该应用类型不存在(应用类型[%s])", key);
|
||||
}
|
||||
|
||||
public static Boolean isApplicationType(String key) {
|
||||
for (ApplicationType value : ApplicationType.values()) {
|
||||
if (StringUtils.equalsIgnoreCase(value.getKey(), key)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("网关路由配置")
|
||||
public class GatewayRouteConfig {
|
||||
@ApiModelProperty(value = "路由标识")
|
||||
private String id;
|
||||
@ApiModelProperty(value = "目标地址")
|
||||
private String uri;
|
||||
@ApiModelProperty(value = "转发规则")
|
||||
private List<String> predicates;
|
||||
@ApiModelProperty(value = "过滤规则")
|
||||
private List<String> filters;
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("网关安全认证配置")
|
||||
public class GatewaySafetyConfig {
|
||||
@ApiModelProperty(value = "允许请求来源")
|
||||
private List<String> allowedOriginPatterns;
|
||||
@ApiModelProperty(value = "允许请求头")
|
||||
private List<String> allowedHeaders;
|
||||
@ApiModelProperty(value = "预检请求缓存时间")
|
||||
private Integer maxAge=360000;
|
||||
@ApiModelProperty(value = "允许请求方法")
|
||||
private List<String> allowedMethods;
|
||||
@ApiModelProperty(value = "允许证书")
|
||||
private Boolean allowCredentials = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("网关白名单配置")
|
||||
public class GatewayWhitelistConfig {
|
||||
@ApiModelProperty(value = "白名单列表")
|
||||
private List<String> whites;
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.microservices.common.core.web.page.GenericsTableDataInfo;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S事件")
|
||||
public class K8SEvent {
|
||||
@ApiModelProperty(value = "事件id")
|
||||
private String docId;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ApiModelProperty(value = "发生时间")
|
||||
private Date occurredTime;
|
||||
@ApiModelProperty(value = "操作类型/异常原因")
|
||||
private String reason;
|
||||
@ApiModelProperty(value = "事件发生对象")
|
||||
private String object;
|
||||
@ApiModelProperty(value = "事件发生子对象")
|
||||
private String childObject;
|
||||
@ApiModelProperty(value = "所处命名空间")
|
||||
private String namespace;
|
||||
@ApiModelProperty(value = "运行结果/详细信息")
|
||||
private String message;
|
||||
|
||||
public static GenericsTableDataInfo<K8SEvent> toK8SEventTable(JSONObject esQueryRes) {
|
||||
List<K8SEvent> k8SEventList = new ArrayList<>();
|
||||
Long total = getK8SEventTotal(esQueryRes, k8SEventList);
|
||||
return new GenericsTableDataInfo<>(k8SEventList, total);
|
||||
}
|
||||
|
||||
public static List<K8SEvent> toK8SEventList(JSONObject esQueryRes) {
|
||||
List<K8SEvent> k8SEventList = new ArrayList<>();
|
||||
getK8SEventTotal(esQueryRes, k8SEventList);
|
||||
return k8SEventList;
|
||||
}
|
||||
|
||||
private static Long getK8SEventTotal(JSONObject esQueryRes, List<K8SEvent> k8SEventList) {
|
||||
Long total = 0L;
|
||||
if (esQueryRes.getJSONObject("hits") != null && esQueryRes.getJSONObject("hits").getJSONArray("hits") != null) {
|
||||
JSONObject hits = esQueryRes.getJSONObject("hits");
|
||||
JSONArray dataHits = hits.getJSONArray("hits");
|
||||
|
||||
for (int i = 0; i < dataHits.size(); i++) {
|
||||
JSONObject dataHit = dataHits.getJSONObject(i);
|
||||
K8SEvent k8SEvent = new K8SEvent();
|
||||
k8SEvent.setDocId(dataHit.getString("_id"));
|
||||
JSONObject source = dataHit.getJSONObject("_source");
|
||||
k8SEvent.setOccurredTime(source.getDate("lastTimestamp"));
|
||||
k8SEvent.setReason(source.getString("reason"));
|
||||
if (source.getJSONObject("involvedObject") != null) {
|
||||
JSONObject involvedObject = source.getJSONObject("involvedObject");
|
||||
k8SEvent.setObject(String.format("%s:%s", involvedObject.getString("kind"), involvedObject.getString("name")));
|
||||
k8SEvent.setChildObject(involvedObject.getString("fieldPath"));
|
||||
k8SEvent.setNamespace(involvedObject.getString("namespace"));
|
||||
}
|
||||
|
||||
k8SEvent.setMessage(source.getString("message"));
|
||||
k8SEventList.add(k8SEvent);
|
||||
}
|
||||
total = hits.getJSONObject("total").getLong("value");
|
||||
}
|
||||
return total;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S资源占用情况")
|
||||
public class K8SResourceUsage {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@ApiModelProperty(value = "发生时间")
|
||||
private Date occurredTime;
|
||||
@ApiModelProperty(value = "资源类型")
|
||||
private String resourceType;
|
||||
@ApiModelProperty(value = "资源对象")
|
||||
private String resourceObject;
|
||||
@ApiModelProperty(value = "资源占用情况")
|
||||
private String message;
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.microservices.mon.k8s.utils.MonUtils;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S应用")
|
||||
public class K8sApplication {
|
||||
|
||||
@ApiModelProperty(value = "应用Id")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "应用别名")
|
||||
private String alias;
|
||||
|
||||
@ApiModelProperty(value = "应用类型")
|
||||
private String kind;
|
||||
|
||||
@ApiModelProperty(value = "所属命名空间")
|
||||
private String namespace;
|
||||
|
||||
@ApiModelProperty(value = "副本数量")
|
||||
private Integer replicas;
|
||||
|
||||
@ApiModelProperty(value = "有效副本数量(当有效副本数为0时代表应用失败呈现红色;当有效副本数大于0但小于副本数时代表应用部分失败呈现橙色;当有效副本数等于副本数代表应用正常呈现蓝色)")
|
||||
private Integer readyReplicas;
|
||||
|
||||
@ApiModelProperty(value = "容器选择器")
|
||||
private String podSelector;
|
||||
|
||||
@ApiModelProperty(value = "Docker镜像")
|
||||
private String dockerImage;
|
||||
|
||||
@ApiModelProperty(value = "重启次数")
|
||||
private Integer restartCount;
|
||||
|
||||
@ApiModelProperty(value = "存活时间")
|
||||
private String survivalTime;
|
||||
|
||||
@ApiModelProperty(value = "运行状态")
|
||||
private K8sApplicationAndPodState state;
|
||||
|
||||
@ApiModelProperty(value = "暂停编排")
|
||||
private Boolean paused;
|
||||
|
||||
private List<K8sApplicationPod> podList;
|
||||
|
||||
// public void setDockerImage(String dockerImage) {
|
||||
// this.dockerImage = MonUtils.getDockerImage(dockerImage);
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("应用状态")
|
||||
public class K8sApplicationAndPodState {
|
||||
|
||||
@ApiModelProperty(value = "状态标识")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "应用展示名称(中文)")
|
||||
private String alias;
|
||||
|
||||
@ApiModelProperty(value = "是否错误")
|
||||
private Boolean isError;
|
||||
|
||||
@ApiModelProperty(value = "状态消息")
|
||||
private String message;
|
||||
|
||||
public static K8sApplicationAndPodState k8sApplicationStopState(String stateName) {
|
||||
K8sApplicationAndPodState state = new K8sApplicationAndPodState();
|
||||
state.setName(stateName);
|
||||
state.setIsError(false);
|
||||
state.setMessage("");
|
||||
state.setApplicationAliasByName(stateName);
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setApplicationAliasByName(String name) {
|
||||
this.name = name;
|
||||
if ("active".equalsIgnoreCase(name)) {
|
||||
this.alias = "运行中";
|
||||
} else if ("updating".equalsIgnoreCase(name)) {
|
||||
this.alias = "更新中";
|
||||
} else if ("in-progress".equalsIgnoreCase(name)) {
|
||||
this.alias = "处理中";
|
||||
} else if ("error".equalsIgnoreCase(name)) {
|
||||
this.alias = "运行失败";
|
||||
} else if ("paused".equalsIgnoreCase(name)) {
|
||||
this.alias = "暂停编排";
|
||||
} else if ("pending".equalsIgnoreCase(name)) {
|
||||
this.alias = "等待中";
|
||||
} else if ("stop".equalsIgnoreCase(name)) {
|
||||
this.alias = "已停止运行";
|
||||
} else {
|
||||
this.alias = name;
|
||||
}
|
||||
}
|
||||
|
||||
public void setPodAliasAndErrorByName(String name) {
|
||||
this.name = name;
|
||||
this.isError=true;
|
||||
|
||||
if ("imagePullBackOff".equalsIgnoreCase(name)) {
|
||||
this.alias = "镜像拉取失败";
|
||||
} else if ("pending".equalsIgnoreCase(name)) {
|
||||
this.alias = "等待中";
|
||||
this.isError=false;
|
||||
} else if ("running".equalsIgnoreCase(name)) {
|
||||
this.alias = "运行中";
|
||||
this.isError=false;
|
||||
} else if ("podScheduled".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器已调度";
|
||||
this.isError=false;
|
||||
} else if ("containersReady".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器已就绪";
|
||||
this.isError=false;
|
||||
} else if ("initialized".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器已初始化";
|
||||
this.isError=false;
|
||||
} else if ("ready".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器已准备就绪";
|
||||
this.isError=false;
|
||||
} else if ("crashLoopBackOff".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器崩溃循环重启";
|
||||
} else if ("invalidImageName".equalsIgnoreCase(name)) {
|
||||
this.alias = "无法解析镜像名称";
|
||||
} else if ("imageInspectError".equalsIgnoreCase(name)) {
|
||||
this.alias = "无法校验镜像";
|
||||
} else if ("errImageNeverPull".equalsIgnoreCase(name)) {
|
||||
this.alias = "策略禁止拉取镜像";
|
||||
} else if ("registryUnavailable".equalsIgnoreCase(name)) {
|
||||
this.alias = "连接不到镜像中心";
|
||||
} else if ("errImagePull".equalsIgnoreCase(name)) {
|
||||
this.alias = "拉取镜像出错";
|
||||
} else if ("createContainerConfigError".equalsIgnoreCase(name)) {
|
||||
this.alias = "不能创建容器配置";
|
||||
} else if ("createContainerError".equalsIgnoreCase(name)) {
|
||||
this.alias = "创建容器失败";
|
||||
} else if ("runContainerError".equalsIgnoreCase(name)) {
|
||||
this.alias = "启动容器失败";
|
||||
} else if ("postStartHookError".equalsIgnoreCase(name)) {
|
||||
this.alias = "执行hook报错";
|
||||
} else if ("containersNotInitialized".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器未初始化完毕";
|
||||
} else if ("containersNotReady".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器未准备完毕";
|
||||
} else if ("containerCreating".equalsIgnoreCase(name)) {
|
||||
this.alias = "容器创建中";
|
||||
this.isError=false;
|
||||
} else if ("podInitializing".equalsIgnoreCase(name)) {
|
||||
this.alias = "Pod 初始化中";
|
||||
this.isError=false;
|
||||
} else if ("dockerDaemonNotReady".equalsIgnoreCase(name)) {
|
||||
this.alias = "Docker 未完全启动";
|
||||
} else if ("networkPluginNotReady".equalsIgnoreCase(name)) {
|
||||
this.alias = "网络插件未完全启动";
|
||||
} else if ("evicted".equalsIgnoreCase(name)) {
|
||||
this.alias = "Pod 被驱赶";
|
||||
} else if ("terminating".equalsIgnoreCase(name)) {
|
||||
this.alias = "删除中";
|
||||
this.isError=false;
|
||||
} else {
|
||||
this.alias = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S应用环境变量")
|
||||
public class K8sApplicationEnv {
|
||||
|
||||
@ApiModelProperty(value = "环境变量类型")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty(value = "环境变量键")
|
||||
private String key;
|
||||
|
||||
@ApiModelProperty(value = "环境变量值")
|
||||
private JSONObject valueObj;
|
||||
|
||||
/**
|
||||
* 将 Kubernetes 容器 env 数组中的单个元素(JSONObject 形式)转换成内部统一的 K8sApplicationEnv 对象。
|
||||
*
|
||||
* <p>支持解析以下四种 value 来源:</p>
|
||||
* <ul>
|
||||
* <li>普通键值对:{@code {"name":"KEY","value":"VAL"}}</li>
|
||||
* <li>资源字段引用:{@code {"name":"CPU_LIMIT","valueFrom":{"resourceFieldRef":{...}}}}</li>
|
||||
* <li>ConfigMap 键引用:{@code {"name":"CM_KEY","valueFrom":{"configMapKeyRef":{...}}}}</li>
|
||||
* <li>Secret 键引用:{@code {"name":"SECRET_KEY","valueFrom":{"secretKeyRef":{...}}}}</li>
|
||||
* <li>Pod 字段引用:{@code {"name":"POD_IP","valueFrom":{"fieldRef":{...}}}}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param envJsonObject 单条 env 的原始 JSON 对象;允许为 null
|
||||
* @return 转换后的 K8sApplicationEnv 实例;无法识别或入参为 null 时返回 null
|
||||
*/
|
||||
public static K8sApplicationEnv envJsonObjectToK8sApplicationEnv(JSONObject envJsonObject) {
|
||||
K8sApplicationEnv k8sApplicationEnv = null;
|
||||
if (envJsonObject != null) {
|
||||
JSONObject valueObj = new JSONObject();
|
||||
if (envJsonObject.containsKey("value")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envJsonObject.getString("name"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.KEY_VALUE_PAIR.getKey());
|
||||
valueObj.put("value", envJsonObject.getString("value"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
} else if (envJsonObject.containsKey("valueFrom")) {
|
||||
JSONObject valueFromJson = envJsonObject.getJSONObject("valueFrom");
|
||||
if (valueFromJson.containsKey("resourceFieldRef")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envJsonObject.getString("name"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.RESOURCE.getKey());
|
||||
JSONObject resourceFieldRef = valueFromJson.getJSONObject("resourceFieldRef");
|
||||
valueObj.put("name", resourceFieldRef.getString("containerName"));
|
||||
valueObj.put("key", resourceFieldRef.getString("resource"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
} else if (valueFromJson.containsKey("configMapKeyRef")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envJsonObject.getString("name"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.CONFIG_MAP_KEY.getKey());
|
||||
JSONObject configMapKeyRef = valueFromJson.getJSONObject("configMapKeyRef");
|
||||
valueObj.put("name", configMapKeyRef.getString("name"));
|
||||
valueObj.put("key", configMapKeyRef.getString("key"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
} else if (valueFromJson.containsKey("secretKeyRef")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envJsonObject.getString("name"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.SECRET_KEY.getKey());
|
||||
JSONObject secretKeyRef = valueFromJson.getJSONObject("secretKeyRef");
|
||||
valueObj.put("name", secretKeyRef.getString("name"));
|
||||
valueObj.put("key", secretKeyRef.getString("key"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
} else if (valueFromJson.containsKey("fieldRef")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envJsonObject.getString("name"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.POD_FIELD.getKey());
|
||||
JSONObject fieldRef = valueFromJson.getJSONObject("fieldRef");
|
||||
valueObj.put("value", fieldRef.getString("fieldPath"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return k8sApplicationEnv;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将 Kubernetes 容器 envFrom 数组中的单个元素(JSONObject 形式)转换成内部统一的 K8sApplicationEnv 对象。
|
||||
*
|
||||
* <p>支持解析以下两种来源:</p>
|
||||
* <ul>
|
||||
* <li>整个 ConfigMap:{@code {"prefix":"PRE_","configMapRef":{"name":"cm-name"}}}</li>
|
||||
* <li>整个 Secret:{@code {"prefix":"PRE_","secretRef":{"name":"secret-name"}}}</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>注意:prefix 可能为 null。</p>
|
||||
*
|
||||
* @param envFromJson 单条 envFrom 的原始 JSON 对象;允许为 null
|
||||
* @return 转换后的 K8sApplicationEnv 实例;无法识别或入参为 null 时返回 null
|
||||
*/
|
||||
public static K8sApplicationEnv envFromJsonObjectToK8sApplicationEnv(JSONObject envFromJson) {
|
||||
K8sApplicationEnv k8sApplicationEnv = null;
|
||||
if (envFromJson != null) {
|
||||
JSONObject valueObj = new JSONObject();
|
||||
if (envFromJson.containsKey("configMapRef")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envFromJson.getString("prefix"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.CONFIGMAP.getKey());
|
||||
JSONObject configMapRef = envFromJson.getJSONObject("configMapRef");
|
||||
valueObj.put("name", configMapRef.getString("name"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
} else if (envFromJson.containsKey("secretRef")) {
|
||||
k8sApplicationEnv = new K8sApplicationEnv();
|
||||
k8sApplicationEnv.setKey(envFromJson.getString("prefix"));
|
||||
k8sApplicationEnv.setType(ApplicationEnvType.SECRET.getKey());
|
||||
JSONObject secretRef = envFromJson.getJSONObject("secretRef");
|
||||
valueObj.put("name", secretRef.getString("name"));
|
||||
k8sApplicationEnv.setValueObj(valueObj);
|
||||
}
|
||||
}
|
||||
return k8sApplicationEnv;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S应用环境变量")
|
||||
public class K8sApplicationEnvOptionalParameter {
|
||||
|
||||
@ApiModelProperty(value = "环境变量参数类型")
|
||||
private String type;
|
||||
|
||||
@ApiModelProperty(value = "环境变量参数名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "环境变量参数键值")
|
||||
private List<String> keys;
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.microservices.mon.k8s.utils.MonUtils;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S容器")
|
||||
public class K8sApplicationPod {
|
||||
|
||||
@ApiModelProperty(value = "容器Id")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "容器名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "所属命名空间")
|
||||
private String namespace;
|
||||
|
||||
@ApiModelProperty(value = "容器Ip")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "重启次数")
|
||||
private Integer restartCount;
|
||||
|
||||
@ApiModelProperty(value = "运行状态")
|
||||
private K8sApplicationAndPodState state;
|
||||
|
||||
@ApiModelProperty(value = "是否正常运行")
|
||||
private Boolean isRunning;
|
||||
|
||||
@ApiModelProperty(value = "存活时间")
|
||||
private String survivalTime;
|
||||
|
||||
@ApiModelProperty(value = "所有权")
|
||||
private String serviceAccountName;
|
||||
|
||||
@ApiModelProperty(value = "容器端口")
|
||||
private String ports;
|
||||
|
||||
@ApiModelProperty(value = "Docker镜像")
|
||||
private String dockerImage;
|
||||
|
||||
@ApiModelProperty(value = "副本数量")
|
||||
private Integer replicas;
|
||||
|
||||
@ApiModelProperty(value = "有效副本数量")
|
||||
private Integer readyReplicas;
|
||||
|
||||
@ApiModelProperty(value = "所属堆栈")
|
||||
private String stack;
|
||||
|
||||
@ApiModelProperty(value = "创建时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date createdTime;
|
||||
|
||||
// public void setDockerImage(String dockerImage) {
|
||||
// this.dockerImage = MonUtils.getDockerImage(dockerImage);
|
||||
// }
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("集群节点")
|
||||
public class K8sClusterNode {
|
||||
@ApiModelProperty(value = "节点标识")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "节点名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "节点IP")
|
||||
private String ip;
|
||||
|
||||
@ApiModelProperty(value = "节点角色(Master/Worker)")
|
||||
private String role;
|
||||
|
||||
@ApiModelProperty(value = "是否就绪")
|
||||
private Boolean Ready;
|
||||
}
|
||||
|
|
@ -0,0 +1,116 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.mon.k8s.domain.vo.PrometheusResVo;
|
||||
import com.microservices.mon.k8s.domain.vo.PrometheusResultVo;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("集群状态")
|
||||
public class K8sClusterStatus {
|
||||
@ApiModelProperty(value = "集群节点数量")
|
||||
private Integer nodeCount;
|
||||
|
||||
@ApiModelProperty(value = "不可用节点数量")
|
||||
private Integer unavailableNodeCount;
|
||||
|
||||
@ApiModelProperty(value = "容器使用率")
|
||||
private Float podUsage;
|
||||
|
||||
@ApiModelProperty(value = "CPU使用率")
|
||||
private Float cpuUsage;
|
||||
|
||||
@ApiModelProperty(value = "内存使用率")
|
||||
private Float memoryUsage;
|
||||
|
||||
@ApiModelProperty(value = "最近24小时请求总数")
|
||||
private Long totalRequestCountToday;
|
||||
|
||||
@ApiModelProperty(value = "最近24小时请求平均处理时间(单位:ms)")
|
||||
private Float averageRequestProcessingTimeToday;
|
||||
|
||||
@ApiModelProperty(value = "最近24小时请求成功率")
|
||||
private Float requestSuccessRateToday;
|
||||
|
||||
@ApiModelProperty(value = "微服务应用数量")
|
||||
private Integer microserviceApplicationCount;
|
||||
|
||||
@ApiModelProperty(value = "最近24小时微服务重启次数")
|
||||
private Integer microserviceRestartCountToday;
|
||||
|
||||
@ApiModelProperty(value = "微服务Pod运行状态(Key代表状态,Value代表数量)")
|
||||
private HashMap<String, Integer> podStatus;
|
||||
|
||||
public void setNodeCount(PrometheusResVo prometheusResVo) {
|
||||
this.nodeCount = Integer.parseInt(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setUnavailableNodeCount(PrometheusResVo prometheusResVo) {
|
||||
this.unavailableNodeCount = Integer.parseInt(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setCpuUsage(PrometheusResVo prometheusResVo) {
|
||||
this.cpuUsage = Float.parseFloat(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setPodUsage(PrometheusResVo prometheusResVo) {
|
||||
this.podUsage = Float.parseFloat(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setMemoryUsage(PrometheusResVo prometheusResVo) {
|
||||
this.memoryUsage = Float.parseFloat(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setTotalRequestCountToday(PrometheusResVo prometheusResVo) {
|
||||
this.totalRequestCountToday = Long.parseLong(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setAverageRequestProcessingTimeToday(PrometheusResVo prometheusResVo) {
|
||||
this.averageRequestProcessingTimeToday = Float.parseFloat(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setRequestSuccessRateToday(PrometheusResVo prometheusResVo) {
|
||||
this.requestSuccessRateToday = Float.parseFloat(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setMicroserviceApplicationCount(List<K8sNamespace> k8sNamespaceList) {
|
||||
this.microserviceApplicationCount = k8sNamespaceList.stream().map(x -> x.getApplicationList().size()).reduce(0, Integer::sum);
|
||||
}
|
||||
|
||||
public void setMicroserviceRestartCountToday(PrometheusResVo prometheusResVo) {
|
||||
this.microserviceRestartCountToday = (int) Float.parseFloat(PrometheusResVo.getPromStringValue(prometheusResVo));
|
||||
}
|
||||
|
||||
public void setPodStatus(PrometheusResVo prometheusResVo) {
|
||||
HashMap<String, Integer> podStatus = new HashMap<>();
|
||||
List<PrometheusResultVo> resultList = PrometheusResVo.getPrometheusResultVoList(prometheusResVo);
|
||||
for (PrometheusResultVo result : resultList) {
|
||||
Integer value = result.getValue().getIntValue(1);
|
||||
switch (result.getMetric().getString("phase")) {
|
||||
case "Running":
|
||||
podStatus.put("运行中", value);
|
||||
break;
|
||||
case "Pending":
|
||||
podStatus.put("等待中", value);
|
||||
break;
|
||||
case "Succeeded":
|
||||
podStatus.put("运行已完成", value);
|
||||
break;
|
||||
case "Unknown":
|
||||
podStatus.put("未知", value);
|
||||
break;
|
||||
case "Failed":
|
||||
podStatus.put("运行失败", value);
|
||||
}
|
||||
}
|
||||
this.podStatus = podStatus;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("命名空间")
|
||||
public class K8sNamespace {
|
||||
@ApiModelProperty(value = "命名空间标识")
|
||||
private String id;
|
||||
|
||||
@ApiModelProperty(value = "命名空间键值")
|
||||
private String key;
|
||||
|
||||
@ApiModelProperty(value = "命名空间名称")
|
||||
private String name;
|
||||
|
||||
@ApiModelProperty(value = "命名空间别名(中文)")
|
||||
private String alias;
|
||||
|
||||
@ApiModelProperty(value = "应用列表")
|
||||
private List<K8sApplication> applicationList;
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S Node状态")
|
||||
public class K8sNodeStatus {
|
||||
@ApiModelProperty(value = "节点IP")
|
||||
private String nodeIp;
|
||||
|
||||
@ApiModelProperty(value = "CPU使用率")
|
||||
private Float cpuUsage;
|
||||
|
||||
@ApiModelProperty(value = "内存使用率")
|
||||
private Float memoryUsage;
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S容器运行状态监控")
|
||||
public class K8sPodContainerMetric {
|
||||
@ApiModelProperty(value = "容器名称")
|
||||
private String podName;
|
||||
|
||||
@ApiModelProperty(value = "指标值")
|
||||
private List<MetricCommonData> data;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S容器运行状态监控总览")
|
||||
public class K8sPodContainerMetricOverview {
|
||||
@ApiModelProperty(value = "容器名称")
|
||||
private String podName;
|
||||
|
||||
@ApiModelProperty(value = "CPU使用率(单位:%)")
|
||||
private List<MetricCommonData> cpuUsage;
|
||||
|
||||
@ApiModelProperty(value = "内存使用情况(单位:byte,需前端换算)")
|
||||
private List<MetricCommonData> memoryUsage;
|
||||
|
||||
@ApiModelProperty(value = "磁盘写入情况(单位:byte/s,需前端换算)")
|
||||
private List<MetricCommonData> diskWrites;
|
||||
|
||||
@ApiModelProperty(value = "磁盘读取情况(单位:byte/s,需前端换算)")
|
||||
private List<MetricCommonData> diskReads;
|
||||
|
||||
@ApiModelProperty(value = "网络接收情况(单位:byte/s,需前端换算)")
|
||||
private List<MetricCommonData> networkReception;
|
||||
|
||||
@ApiModelProperty(value = "网络发送情况(单位:byte/s,需前端换算)")
|
||||
private List<MetricCommonData> networkTransmission;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.microservices.mon.k8s.domain.vo.PrometheusResVo;
|
||||
import com.microservices.mon.k8s.domain.vo.PrometheusResultVo;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S容器状态")
|
||||
public class K8sPodContainerStatus {
|
||||
@ApiModelProperty(value = "容器名称")
|
||||
private String podName;
|
||||
|
||||
@ApiModelProperty(value = "CPU使用率")
|
||||
private Float cpuUsage;
|
||||
|
||||
@ApiModelProperty(value = "内存使用情况")
|
||||
private String memoryUsage;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S容器启停时间")
|
||||
public class K8sPodStartStopDate {
|
||||
@ApiModelProperty(value = "容器名称")
|
||||
private String podName;
|
||||
|
||||
@ApiModelProperty(value = "启动时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date startDate;
|
||||
|
||||
@ApiModelProperty(value = "停止时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date stopDate;
|
||||
|
||||
private Boolean isRunning = true;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("K8S容器启停状态")
|
||||
public class K8sPodStartStopStatus {
|
||||
@ApiModelProperty(value = "启动数")
|
||||
private Integer startCount;
|
||||
|
||||
@ApiModelProperty(value = "总数")
|
||||
private Integer podCount;
|
||||
|
||||
@ApiModelProperty(value = "启停时间列表")
|
||||
private List<K8sPodStartStopDate> podStartStopDateList;
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ApiModel("链路追踪应用")
|
||||
public class LinkTrackingApplication {
|
||||
@ApiModelProperty(value = "序号")
|
||||
private Integer index;
|
||||
@ApiModelProperty(value = "应用Id")
|
||||
private String id;
|
||||
@ApiModelProperty(value = "应用标识")
|
||||
private String key;
|
||||
@ApiModelProperty(value = "应用名称")
|
||||
private String applicationName;
|
||||
@ApiModelProperty(value = "负载")
|
||||
private Float load;
|
||||
@ApiModelProperty(value = "成功率")
|
||||
private Float successRate;
|
||||
@ApiModelProperty(value = "延迟")
|
||||
private Float latency;
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel("指标通用对象")
|
||||
public class MetricCommonData {
|
||||
|
||||
@ApiModelProperty(value = "时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date date;
|
||||
|
||||
@ApiModelProperty(value = "指标值")
|
||||
private Float value;
|
||||
|
||||
public static List<MetricCommonData> prometheusResultVoToMetric(JSONArray prometheusResultValues) {
|
||||
List<MetricCommonData> metricCommonDataList = new ArrayList<>();
|
||||
for (int i = 0; i < prometheusResultValues.size(); i++) {
|
||||
JSONArray value = prometheusResultValues.getJSONArray(i);
|
||||
MetricCommonData metricCommonData = new MetricCommonData();
|
||||
metricCommonData.setDate(new Date(value.getLong(0) * 1000));
|
||||
String valueStr = String.format("%.2f", value.getFloatValue(1));
|
||||
metricCommonData.setValue(Float.parseFloat(valueStr));
|
||||
metricCommonDataList.add(metricCommonData);
|
||||
}
|
||||
metricCommonDataList.sort(Comparator.comparing(MetricCommonData::getDate));
|
||||
return metricCommonDataList;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.microservices.mon.k8s.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public enum SkywalkingMetricType {
|
||||
SERVICE_CPM("cpmFunction", "cpmVariable", "service_cpm"),
|
||||
SERVICE_SLA("slaFunction", "slaVariable", "service_sla"),
|
||||
SERVICE_RESP_TIME("respTimeFunction", "respTimeVariable", "service_resp_time");
|
||||
private final String functionName;
|
||||
private final String functionVariable;
|
||||
private final String metricKey;
|
||||
|
||||
SkywalkingMetricType(String functionName, String functionVariable, String metricKey) {
|
||||
this.functionName = functionName;
|
||||
this.functionVariable = functionVariable;
|
||||
this.metricKey = metricKey;
|
||||
}
|
||||
public String getFunctionVariable(Integer index) {
|
||||
return this.functionVariable+index;
|
||||
}
|
||||
public String getFunctionName(Integer index) {
|
||||
return this.functionName+index;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author OTTO
|
||||
*/
|
||||
@Data
|
||||
public class ApplicationEnvTypeVo {
|
||||
private String key;
|
||||
private String alias;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.microservices.common.core.exception.ServiceException;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author OTTO
|
||||
*/
|
||||
@Data
|
||||
public class ApplicationTypeVo {
|
||||
private String key;
|
||||
private String fullName;
|
||||
private String description;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class CommonTypeVo {
|
||||
|
||||
private String name;
|
||||
private String key;
|
||||
|
||||
public static List<CommonTypeVo> eventReasonListToCommonTypeVoList(JSONObject eventReasonListQueryRes) {
|
||||
List<CommonTypeVo> commonTypeVoList = new ArrayList<>();
|
||||
if (eventReasonListQueryRes != null && eventReasonListQueryRes.getJSONObject("aggregations") != null
|
||||
&& eventReasonListQueryRes.getJSONObject("aggregations").getJSONObject("distinct_reasons") != null
|
||||
&& eventReasonListQueryRes.getJSONObject("aggregations").getJSONObject("distinct_reasons").getJSONArray("buckets") != null) {
|
||||
JSONArray eventReasonList = eventReasonListQueryRes.getJSONObject("aggregations").getJSONObject("distinct_reasons").getJSONArray("buckets");
|
||||
for (int i = 0; i < eventReasonList.size(); i++) {
|
||||
JSONObject eventReason = eventReasonList.getJSONObject(i);
|
||||
CommonTypeVo commonTypeVo = new CommonTypeVo();
|
||||
commonTypeVo.setName(eventReason.getString("key"));
|
||||
commonTypeVo.setKey(eventReason.getString("key"));
|
||||
commonTypeVoList.add(commonTypeVo);
|
||||
}
|
||||
}
|
||||
return commonTypeVoList;
|
||||
}
|
||||
|
||||
public static List<CommonTypeVo> resourceObjectToCommonTypeVoList(List<PrometheusResultVo> resultList) {
|
||||
List<CommonTypeVo> commonTypeVoList = new ArrayList<>();
|
||||
for (PrometheusResultVo resultVo : resultList) {
|
||||
JSONObject metric = resultVo.getMetric();
|
||||
String nodeInstance = metric.getString("instance");
|
||||
String nodeIp = metric.getString("ip");
|
||||
CommonTypeVo commonTypeVo = new CommonTypeVo();
|
||||
commonTypeVo.setName(String.format("%s(%s)", nodeInstance, nodeIp));
|
||||
commonTypeVo.setKey(nodeIp);
|
||||
commonTypeVoList.add(commonTypeVo);
|
||||
}
|
||||
return commonTypeVoList;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PrometheusDataVo {
|
||||
// 查询结果类型
|
||||
String resultType;
|
||||
// 应用类型
|
||||
List<PrometheusResultVo> result;
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class PrometheusResVo {
|
||||
// 状态(success代表成功)
|
||||
String status;
|
||||
// 数据
|
||||
PrometheusDataVo data;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return "success".equals(status)
|
||||
&& data != null
|
||||
&& data.getResult() != null
|
||||
&& !data.getResult().isEmpty();
|
||||
}
|
||||
|
||||
public static String getPromStringValue(PrometheusResVo prometheusResVo) {
|
||||
String value = "";
|
||||
if (prometheusResVo != null && prometheusResVo.isSuccess()) {
|
||||
PrometheusResultVo result = prometheusResVo.getData().getResult().get(0);
|
||||
return result.getValue().getString(1);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public static List<PrometheusResultVo> getPrometheusResultVoList(PrometheusResVo prometheusResVo) {
|
||||
if (prometheusResVo != null && prometheusResVo.isSuccess()) {
|
||||
return prometheusResVo.getData().getResult();
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class PrometheusResultVo {
|
||||
// 指标数据
|
||||
JSONObject metric;
|
||||
// 指标值
|
||||
JSONArray value;
|
||||
// 范围查询时指标值
|
||||
JSONArray values;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RancherApplicationStateVo {
|
||||
|
||||
// Daemonsets-期望数量
|
||||
Integer desiredNumberScheduled;
|
||||
|
||||
// Daemonsets-就绪数量
|
||||
Integer numberReady;
|
||||
|
||||
// Deploy/Stateful-就绪副本数
|
||||
Integer readyReplicas;
|
||||
|
||||
// Stateful-有效副本数
|
||||
Integer availableReplicas;
|
||||
|
||||
// Deploy/Stateful-副本数量
|
||||
Integer replicas;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.context.SecurityContextHolder;
|
||||
import com.microservices.common.core.utils.DateUtils;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.mon.k8s.domain.K8sApplication;
|
||||
import com.microservices.mon.k8s.domain.K8sApplicationAndPodState;
|
||||
import com.microservices.mon.k8s.domain.K8sApplicationPod;
|
||||
import com.microservices.mon.k8s.utils.MonUtils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Data
|
||||
public class RancherApplicationVo {
|
||||
// 标识
|
||||
String id;
|
||||
// 应用类型
|
||||
String kind;
|
||||
// 元数据
|
||||
RancherMetadataVo metadata;
|
||||
// 状态
|
||||
RancherApplicationStateVo status;
|
||||
// 规格
|
||||
JSONObject spec;
|
||||
|
||||
|
||||
public K8sApplication toK8sApplication() {
|
||||
K8sApplication target = new K8sApplication();
|
||||
BeanUtils.copyProperties(this, target);
|
||||
|
||||
if ("DaemonSet".equals(kind)) {
|
||||
target.setReplicas(status.getDesiredNumberScheduled());
|
||||
target.setReadyReplicas(status.getNumberReady());
|
||||
} else if ("StatefulSet".equals(kind)) {
|
||||
target.setReplicas(status.getReplicas());
|
||||
target.setReadyReplicas(status.getAvailableReplicas());
|
||||
} else {
|
||||
target.setReplicas(status.getReplicas());
|
||||
target.setReadyReplicas(status.getReadyReplicas());
|
||||
}
|
||||
|
||||
if (spec != null) {
|
||||
JSONObject templateObj = spec.getJSONObject("template");
|
||||
if (templateObj != null) {
|
||||
JSONObject specObj = templateObj.getJSONObject("spec");
|
||||
if (specObj != null) {
|
||||
JSONArray containersArray = specObj.getJSONArray("containers");
|
||||
if (containersArray != null && !containersArray.isEmpty()) {
|
||||
JSONObject firstContainer = containersArray.getJSONObject(0);
|
||||
if (firstContainer != null && firstContainer.containsKey("image")) {
|
||||
target.setDockerImage(firstContainer.getString("image"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spec.containsKey("paused")) {
|
||||
target.setPaused(spec.getBoolean("paused"));
|
||||
} else {
|
||||
target.setPaused(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (metadata != null) {
|
||||
target.setName(metadata.getName());
|
||||
target.setAlias(metadata.getName());
|
||||
if (metadata.getAnnotations() != null && metadata.getAnnotations().containsKey("mon-name")) {
|
||||
target.setAlias(metadata.getAnnotations().getString("mon-name"));
|
||||
}
|
||||
|
||||
if (metadata.getState() != null) {
|
||||
target.setState(metadata.getState().toK8sApplicationState());
|
||||
}
|
||||
target.setSurvivalTime(
|
||||
MonUtils.getTimeDifferenceDescription(metadata.getCreationTimestamp())
|
||||
);
|
||||
target.setNamespace(metadata.getNamespace());
|
||||
|
||||
JSONArray relationships = metadata.getRelationships();
|
||||
for (int i = 0; i < relationships.size(); i++) {
|
||||
JSONObject relationship = relationships.getJSONObject(i);
|
||||
if (relationship.containsKey("toType") && "pod".equals(relationship.getString("toType"))) {
|
||||
String selector = relationship.getString("selector");
|
||||
if (StringUtils.isNotEmpty(selector) && selector.contains("=") && selector.split("=").length >= 2) {
|
||||
target.setPodSelector(selector);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(target.getReplicas()==null){
|
||||
target.setReplicas(0);
|
||||
}
|
||||
if(target.getReadyReplicas()==null){
|
||||
target.setReadyReplicas(0);
|
||||
}
|
||||
|
||||
if (target.getReplicas() == 0) {
|
||||
target.setState(K8sApplicationAndPodState.k8sApplicationStopState("stop"));
|
||||
}
|
||||
if(target.getPaused()){
|
||||
target.setState(K8sApplicationAndPodState.k8sApplicationStopState("paused"));
|
||||
}
|
||||
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RancherClusterNodeStateVo {
|
||||
|
||||
// ip地址
|
||||
JSONArray addresses;
|
||||
|
||||
// 资源分配
|
||||
JSONObject allocatable;
|
||||
|
||||
// 节点状况
|
||||
JSONArray conditions;
|
||||
|
||||
// 节点信息
|
||||
JSONObject nodeInfo;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.mon.k8s.domain.K8sApplication;
|
||||
import com.microservices.mon.k8s.domain.K8sClusterNode;
|
||||
import com.microservices.mon.k8s.domain.K8sNamespace;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class RancherClusterNodeVo {
|
||||
// 标识
|
||||
String id;
|
||||
// 元数据
|
||||
RancherMetadataVo metadata;
|
||||
// 节点状态
|
||||
RancherClusterNodeStateVo status;
|
||||
|
||||
public K8sClusterNode toK8sClusterNode() {
|
||||
K8sClusterNode target = new K8sClusterNode();
|
||||
BeanUtils.copyProperties(this, target);
|
||||
if (metadata.getLabels() != null && metadata.getLabels().containsKey("node-role.kubernetes.io/control-plane")) {
|
||||
target.setRole("Master");
|
||||
}else{
|
||||
target.setRole("Worker");
|
||||
}
|
||||
target.setName(metadata.getName());
|
||||
if(status!=null&&status.getAddresses()!=null){
|
||||
JSONArray addresses=status.getAddresses();
|
||||
for (int i = 0; i < addresses.size(); i++) {
|
||||
JSONObject jsonObject = addresses.getJSONObject(i);
|
||||
if (jsonObject.getString("type").equals("InternalIP")) {
|
||||
target.setIp(jsonObject.getString("address"));
|
||||
}
|
||||
}
|
||||
JSONArray conditions=status.getConditions();
|
||||
for (int i = 0; i < conditions.size(); i++) {
|
||||
JSONObject jsonObject = conditions.getJSONObject(i);
|
||||
if (jsonObject.getString("type").equals("Ready")) {
|
||||
target.setReady(jsonObject.getBoolean("status"));
|
||||
}
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.microservices.mon.k8s.domain.K8sApplicationAndPodState;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RancherMetadataState {
|
||||
// 是否错误
|
||||
Boolean error;
|
||||
// 状态消息
|
||||
String message;
|
||||
// 状态名称
|
||||
// 应用状态(name -> active、name -> updating、name -> in-progress、name -> error)
|
||||
// pod状态(name -> imagePullBackOff、name -> containerCreating)
|
||||
String name;
|
||||
// 是否过渡状态
|
||||
Boolean transitioning;
|
||||
|
||||
public K8sApplicationAndPodState toK8sApplicationState() {
|
||||
K8sApplicationAndPodState state = new K8sApplicationAndPodState();
|
||||
state.setName(name);
|
||||
state.setIsError(error);
|
||||
state.setMessage(message);
|
||||
state.setApplicationAliasByName(name);
|
||||
return state;
|
||||
}
|
||||
public K8sApplicationAndPodState toK8sPodState() {
|
||||
K8sApplicationAndPodState state = new K8sApplicationAndPodState();
|
||||
state.setName(name);
|
||||
state.setMessage(message);
|
||||
state.setPodAliasAndErrorByName(name);
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class RancherMetadataVo {
|
||||
// 所属命名空间
|
||||
String namespace;
|
||||
// 创建时间
|
||||
Date creationTimestamp;
|
||||
// 描述
|
||||
JSONObject annotations;
|
||||
// 关联数据
|
||||
JSONArray relationships;
|
||||
// 标签
|
||||
JSONObject labels;
|
||||
// 名称
|
||||
String name;
|
||||
// 状态
|
||||
RancherMetadataState state;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.mon.k8s.domain.K8sNamespace;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RancherNamespaceVo {
|
||||
// 描述
|
||||
JSONObject annotations;
|
||||
//创建时间
|
||||
Date created;
|
||||
// 标识
|
||||
String id;
|
||||
// 标签
|
||||
JSONObject labels;
|
||||
// 名称
|
||||
String name;
|
||||
// 状态
|
||||
String state;
|
||||
|
||||
public K8sNamespace toK8sNamespace() {
|
||||
K8sNamespace target = new K8sNamespace();
|
||||
BeanUtils.copyProperties(this, target);
|
||||
target.setKey(labels.getString("mon-key"));
|
||||
target.setAlias(annotations.getString("mon-name"));
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RancherPodStateVo {
|
||||
|
||||
// Pod状况
|
||||
JSONArray conditions;
|
||||
|
||||
// Pod Ip
|
||||
String podIP;
|
||||
|
||||
// 启动时间
|
||||
Date startTime;
|
||||
|
||||
// 容器状态
|
||||
List<JSONObject> containerStatuses;
|
||||
|
||||
// 运行阶段
|
||||
String phase;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,89 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.common.core.utils.StringUtils;
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.mon.k8s.domain.K8sApplication;
|
||||
import com.microservices.mon.k8s.domain.K8sApplicationPod;
|
||||
import com.microservices.mon.k8s.utils.MonUtils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RancherPodVo {
|
||||
// 标识
|
||||
String id;
|
||||
// 元数据
|
||||
RancherMetadataVo metadata;
|
||||
// 状态
|
||||
RancherPodStateVo status;
|
||||
// 状态
|
||||
JSONObject spec;
|
||||
|
||||
public K8sApplicationPod toK8sApplicationPod() {
|
||||
K8sApplicationPod target = new K8sApplicationPod();
|
||||
BeanUtils.copyProperties(this, target);
|
||||
target.setIp(status.getPodIP());
|
||||
if (metadata != null) {
|
||||
target.setName(metadata.getName());
|
||||
if (metadata.getState() != null) {
|
||||
target.setState(metadata.getState().toK8sPodState());
|
||||
}
|
||||
if (metadata.getLabels() != null) {
|
||||
target.setStack(metadata.getLabels().getString("stack"));
|
||||
}
|
||||
target.setNamespace(metadata.getNamespace());
|
||||
target.setCreatedTime(metadata.getCreationTimestamp());
|
||||
}
|
||||
target.setIsRunning(false);
|
||||
if (status != null) {
|
||||
if (status.getContainerStatuses() != null && !status.getContainerStatuses().isEmpty()) {
|
||||
target.setRestartCount(status.getContainerStatuses().stream().mapToInt(x -> x.getInteger("restartCount")).sum());
|
||||
target.setReadyReplicas(Math.toIntExact(status.getContainerStatuses().stream().filter(x -> x.containsKey("ready") && x.getBoolean("ready")).count()));
|
||||
target.setReplicas(status.getContainerStatuses().size());
|
||||
}
|
||||
if (StringUtils.isNotEmpty(status.phase) && status.phase.equals("Running")) {
|
||||
target.setIsRunning(true);
|
||||
}
|
||||
}
|
||||
List<String> ports = new ArrayList<>();
|
||||
List<String> dockerImages = new ArrayList<>();
|
||||
if (spec != null) {
|
||||
if (spec.containsKey("containers")) {
|
||||
JSONArray containers = spec.getJSONArray("containers");
|
||||
for (int i = 0; i < containers.size(); i++) {
|
||||
JSONObject container = containers.getJSONObject(i);
|
||||
// 设置镜像
|
||||
if (container.containsKey("image")) {
|
||||
dockerImages.add(container.getString("image"));
|
||||
}
|
||||
// 设置端口
|
||||
if (container.containsKey("ports")) {
|
||||
JSONArray portsArray = container.getJSONArray("ports");
|
||||
for (int j = 0; j < portsArray.size(); j++) {
|
||||
JSONObject port = portsArray.getJSONObject(j);
|
||||
String containerPort = port.getString("containerPort");
|
||||
if (StringUtils.isNotEmpty(containerPort)) {
|
||||
ports.add(containerPort);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (spec.containsKey("serviceAccountName")) {
|
||||
target.setServiceAccountName(spec.getString("serviceAccountName"));
|
||||
}
|
||||
}
|
||||
target.setPorts(StringUtils.join(ports, ","));
|
||||
target.setDockerImage(StringUtils.join(dockerImages, ","));
|
||||
|
||||
target.setSurvivalTime(
|
||||
MonUtils.getTimeDifferenceDescription(metadata.getCreationTimestamp())
|
||||
);
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RancherServicePortsVo {
|
||||
|
||||
// 端口名称
|
||||
String name;
|
||||
|
||||
// 映射端口
|
||||
Integer nodePort;
|
||||
|
||||
// 内部端口
|
||||
Integer port;
|
||||
|
||||
// 协议
|
||||
String protocol;
|
||||
|
||||
// 目标端口
|
||||
String targetPort;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RancherServiceSpecVo {
|
||||
|
||||
// 端口映射列表
|
||||
List<RancherServicePortsVo> ports;
|
||||
JSONObject selector;
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
package com.microservices.mon.k8s.domain.vo;
|
||||
|
||||
import com.microservices.common.core.utils.bean.BeanUtils;
|
||||
import com.microservices.mon.k8s.domain.K8sApplication;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RancherServiceVo {
|
||||
// 标识
|
||||
String id;
|
||||
// 元数据
|
||||
RancherMetadataVo metadata;
|
||||
// 规格
|
||||
RancherServiceSpecVo spec;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.microservices.mon.k8s.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.microservices.mon.k8s.domain.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IK8sDashboardService {
|
||||
List<K8sNamespace> getNamespaceDetailList(boolean needPod, String search);
|
||||
|
||||
List<K8sClusterNode> getClusterNodeList();
|
||||
|
||||
List<String> getApplicationPodIdList(String kind, String namespace,String applicationName);
|
||||
|
||||
K8sClusterStatus getClusterStatus();
|
||||
|
||||
List<MetricCommonData> getClusterQps();
|
||||
|
||||
List<ApplicationRequestCountData> getApplicationRequestCount();
|
||||
|
||||
K8sPodContainerStatus getPodContainerStatus(String podName);
|
||||
|
||||
K8sNodeStatus getNodeStatus(String nodeIp);
|
||||
|
||||
List<ApplicationFunction> getApplicationFunction(String kind, String namespace, String applicationName, String podIpList);
|
||||
|
||||
List<K8sNamespace> getK8sNamespaceList();
|
||||
|
||||
List<MetricCommonData> getMetricCommonDataList(JSONObject metricResJson);
|
||||
|
||||
JSONArray getSentinelAppList();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue