From d5ab5ac8f424d95fb578350a8a0236e5c08cdc79 Mon Sep 17 00:00:00 2001 From: Pil0tXia Date: Sat, 30 Sep 2023 22:42:52 +0800 Subject: [PATCH] feat: get nacos config list with OpenAPI --- eventmesh-admin-kotlin/build.gradle.kts | 2 + .../adminkotlin/config/AdminProperties.java | 10 +- .../adminkotlin/config/Constants.java | 12 +- .../controller/SubscriptionController.java | 35 +++++- .../adminkotlin/dto/CommonResponse.java | 22 ++++ .../adminkotlin/model/SubscriptionInfo.java | 15 --- .../service/SubscriptionService.java | 6 +- .../service/impl/EtcdSubscriptionService.java | 8 +- .../impl/NacosSubscriptionService.java | 105 ++++++++++++++++-- .../src/main/resources/application.yml | 10 +- 10 files changed, 187 insertions(+), 38 deletions(-) create mode 100644 eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/dto/CommonResponse.java diff --git a/eventmesh-admin-kotlin/build.gradle.kts b/eventmesh-admin-kotlin/build.gradle.kts index 4150af1415..ad0952c4e7 100644 --- a/eventmesh-admin-kotlin/build.gradle.kts +++ b/eventmesh-admin-kotlin/build.gradle.kts @@ -29,6 +29,7 @@ repositories { // utility val commonsLang3Version by extra("3.13.0") val guavaVersion by extra("32.1.2-jre") // not used for now +val fastjsonVersion by extra("2.0.40") // swagger val springdocVersion by extra("1.7.0") // unit test @@ -47,6 +48,7 @@ dependencies { // utility implementation("org.apache.commons:commons-lang3:${commonsLang3Version}") + implementation("com.alibaba.fastjson2:fastjson2:${fastjsonVersion}") // swagger implementation("org.springdoc:springdoc-openapi-ui:${springdocVersion}") implementation("org.springdoc:springdoc-openapi-javadoc:${springdocVersion}") diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/AdminProperties.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/AdminProperties.java index 73af091c63..cce515e988 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/AdminProperties.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/AdminProperties.java @@ -31,9 +31,15 @@ public static class NacosProperties { private String addr = "127.0.0.1:8848"; - private String username = "nacos"; + private boolean authEnabled; - private String password = "nacos"; + private String username; + + private String password; + + private String accessKey; + + private String secretKey; private String namespace = ""; diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/Constants.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/Constants.java index af37d4f4b8..591e8849b2 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/Constants.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/config/Constants.java @@ -2,9 +2,17 @@ public class Constants { + // config public static final String ADMIN_PROPS_PREFIX = "eventmesh"; - public static final String META_TYPE_NACOS = "nacos"; - public static final String META_TYPE_ETCD = "etcd"; + + // Open-API + public static final String HTTP_PREFIX = "http://"; + public static final String HTTPS_PREFIX = "https://"; + public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; + + // Nacos + public static final String NACOS_LOGIN_API = "/nacos/v1/auth/login"; + public static final String NACOS_CONFIGS_API = "/nacos/v1/cs/configs"; } diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/controller/SubscriptionController.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/controller/SubscriptionController.java index c2ed7c3e27..e76e94339e 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/controller/SubscriptionController.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/controller/SubscriptionController.java @@ -1,10 +1,13 @@ package com.apache.eventmesh.adminkotlin.controller; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; +import com.apache.eventmesh.adminkotlin.dto.CommonResponse; import com.apache.eventmesh.adminkotlin.service.SubscriptionService; import lombok.extern.slf4j.Slf4j; @@ -16,9 +19,37 @@ public class SubscriptionController { @Autowired public SubscriptionService subscriptionService; + /** + * retrieve a specified config + * + * @param dataId nacos config data id (Exact Matching) + * @param group config group (Exact Matching) + * @return the config content + */ @GetMapping("/subscription") - public String listSubscriptions(@RequestParam("page") Integer page, @RequestParam("size") String size, String dataId, String group) { - return subscriptionService.retrieveConfig(dataId, group); + public ResponseEntity retrieveSubscription(@RequestParam("dataId") String dataId, @RequestParam("group") String group) { + CommonResponse response = subscriptionService.retrieveConfig(dataId, group); + if (response.getData() != null) { + return ResponseEntity.ok(response.getData()); + } else { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(response.getMessage()); + } + } + + /** + * retrieve a list of configs + * + * @param page page number + * @param size page size + * @param dataId nacos config data id (Fuzzy Matching) + * @param group config group (Fuzzy Matching) + * @return the config content and config properties + */ + @GetMapping("/subscriptions") + public ResponseEntity listSubscriptions( + @RequestParam(name = "page", defaultValue = "1") Integer page, @RequestParam(name = "size", defaultValue = "10") Integer size, + @RequestParam(name = "dataId", defaultValue = "") String dataId, @RequestParam(name = "group", defaultValue = "") String group) { + return ResponseEntity.ok(subscriptionService.retrieveConfigs(page, size, dataId, group)); } } diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/dto/CommonResponse.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/dto/CommonResponse.java new file mode 100644 index 0000000000..9b5ff70c94 --- /dev/null +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/dto/CommonResponse.java @@ -0,0 +1,22 @@ +package com.apache.eventmesh.adminkotlin.dto; + +import lombok.Data; + +@Data +public class CommonResponse { + + private String data; + + private String message; + + public CommonResponse(String data) { + this.data = data; + } + + public CommonResponse(String message, Exception e) { + this.message = message; + if (e != null) { + this.message += ": " + e.getMessage(); + } + } +} diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/model/SubscriptionInfo.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/model/SubscriptionInfo.java index dbc744b455..14aaef6762 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/model/SubscriptionInfo.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/model/SubscriptionInfo.java @@ -1,19 +1,4 @@ package com.apache.eventmesh.adminkotlin.model; public class SubscriptionInfo { - // TODO - private String configData; - private String errorMessage; - - public SubscriptionInfo(String configData) { - this.configData = configData; - } - - public SubscriptionInfo(String errorMessage, Exception exception) { - this.errorMessage = errorMessage; - if (exception != null) { - this.errorMessage += ": " + exception.getMessage(); - } - } - } diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/SubscriptionService.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/SubscriptionService.java index ac3fab7ff0..efb523f1fb 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/SubscriptionService.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/SubscriptionService.java @@ -1,6 +1,10 @@ package com.apache.eventmesh.adminkotlin.service; +import com.apache.eventmesh.adminkotlin.dto.CommonResponse; + public interface SubscriptionService { - String retrieveConfig(String dataId, String group); + CommonResponse retrieveConfig(String dataId, String group); + + String retrieveConfigs(Integer page, Integer size, String dataId, String group); } diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/EtcdSubscriptionService.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/EtcdSubscriptionService.java index 6e17d0f7b6..10747e8f96 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/EtcdSubscriptionService.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/EtcdSubscriptionService.java @@ -2,6 +2,7 @@ import org.springframework.stereotype.Service; +import com.apache.eventmesh.adminkotlin.dto.CommonResponse; import com.apache.eventmesh.adminkotlin.service.SubscriptionService; import lombok.extern.slf4j.Slf4j; @@ -11,7 +12,12 @@ public class EtcdSubscriptionService implements SubscriptionService { @Override - public String retrieveConfig(String dataId, String group) { + public CommonResponse retrieveConfig(String dataId, String group) { + return null; + } + + @Override + public String retrieveConfigs(Integer page, Integer size, String dataId, String group) { return null; } } diff --git a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/NacosSubscriptionService.java b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/NacosSubscriptionService.java index 0aa37a5d6b..75708591e1 100644 --- a/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/NacosSubscriptionService.java +++ b/eventmesh-admin-kotlin/src/main/java/com/apache/eventmesh/adminkotlin/service/impl/NacosSubscriptionService.java @@ -1,12 +1,28 @@ package com.apache.eventmesh.adminkotlin.service.impl; +import static com.apache.eventmesh.adminkotlin.config.Constants.HTTP_PREFIX; +import static com.apache.eventmesh.adminkotlin.config.Constants.NACOS_CONFIGS_API; +import static com.apache.eventmesh.adminkotlin.config.Constants.NACOS_LOGIN_API; + +import java.util.Collections; import java.util.Properties; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; +import com.alibaba.fastjson2.JSON; import com.alibaba.nacos.api.NacosFactory; +import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigService; import com.apache.eventmesh.adminkotlin.config.AdminProperties; +import com.apache.eventmesh.adminkotlin.dto.CommonResponse; import com.apache.eventmesh.adminkotlin.service.SubscriptionService; import lombok.extern.slf4j.Slf4j; @@ -15,30 +31,95 @@ @Service public class NacosSubscriptionService implements SubscriptionService { - Properties properties = new Properties(); + AdminProperties adminProperties; + + Properties nacosProps = new Properties(); + + RestTemplate restTemplate = new RestTemplate(); public NacosSubscriptionService(AdminProperties adminProperties) { - properties.setProperty("serverAddr", adminProperties.getMeta().getNacos().getAddr()); - properties.setProperty("username", adminProperties.getMeta().getNacos().getUsername()); - properties.setProperty("password", adminProperties.getMeta().getNacos().getPassword()); - properties.setProperty("namespace", adminProperties.getMeta().getNacos().getNamespace()); - properties.setProperty("timeoutMs", String.valueOf(adminProperties.getConfig().getTimeoutMs())); + this.adminProperties = adminProperties; + + nacosProps.setProperty(PropertyKeyConst.SERVER_ADDR, adminProperties.getMeta().getNacos().getAddr()); + if (adminProperties.getMeta().getNacos().isAuthEnabled()) { + if (!adminProperties.getMeta().getNacos().getUsername().isEmpty()) { + nacosProps.setProperty(PropertyKeyConst.USERNAME, adminProperties.getMeta().getNacos().getUsername()); + } + if (!adminProperties.getMeta().getNacos().getPassword().isEmpty()) { + nacosProps.setProperty(PropertyKeyConst.PASSWORD, adminProperties.getMeta().getNacos().getPassword()); + } + if (!adminProperties.getMeta().getNacos().getAccessKey().isEmpty()) { + nacosProps.setProperty(PropertyKeyConst.ACCESS_KEY, adminProperties.getMeta().getNacos().getAccessKey()); + } + if (!adminProperties.getMeta().getNacos().getSecretKey().isEmpty()) { + nacosProps.setProperty(PropertyKeyConst.SECRET_KEY, adminProperties.getMeta().getNacos().getSecretKey()); + } + } + nacosProps.setProperty(PropertyKeyConst.NAMESPACE, adminProperties.getMeta().getNacos().getNamespace()); } + /** + * retrieve a specified config with Nacos SDK + */ @Override - public String retrieveConfig(String dataId, String group) { + public CommonResponse retrieveConfig(String dataId, String group) { ConfigService configService; try { - configService = NacosFactory.createConfigService(properties); + configService = NacosFactory.createConfigService(nacosProps); } catch (Exception e) { log.error("Create Nacos ConfigService error", e); - return "Create Nacos ConfigService error: " + e.getMessage(); + return new CommonResponse("Create Nacos ConfigService error", e); + } + try { + String configData = configService.getConfig(dataId, group, adminProperties.getConfig().getTimeoutMs()); + return new CommonResponse(configData); + } catch (Exception e) { + log.error("Get Nacos config error", e); + return new CommonResponse("Get Nacos config error", e); + } + } + + /** + * retrieve a list of configs with Nacos OpenAPI, because Nacos SDK doesn't support listing and fuzzy matching + */ + @Override + public String retrieveConfigs(Integer page, Integer size, String dataId, String group) { + UriComponentsBuilder urlBuilder = UriComponentsBuilder + .fromHttpUrl(HTTP_PREFIX + nacosProps.getProperty(PropertyKeyConst.SERVER_ADDR) + NACOS_CONFIGS_API) + .queryParam("pageNo", page) + .queryParam("pageSize", size) + .queryParam("dataId", dataId) + .queryParam("group", group) + .queryParam("search", "blur"); + + if (adminProperties.getMeta().getNacos().isAuthEnabled()) { + urlBuilder.queryParam("accessToken", loginGetAccessToken()); } + + ResponseEntity response = restTemplate.getForEntity(urlBuilder.toUriString(), String.class); + return response.getBody(); + } + + /** + * login if auth enabled and return accessToken + */ + private String loginGetAccessToken() { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + MultiValueMap bodyParams = new LinkedMultiValueMap<>(); + bodyParams.put("username", Collections.singletonList(nacosProps.getProperty(PropertyKeyConst.USERNAME))); + bodyParams.put("password", Collections.singletonList(nacosProps.getProperty(PropertyKeyConst.PASSWORD))); + + String loginUrl = HTTP_PREFIX + nacosProps.getProperty(PropertyKeyConst.SERVER_ADDR) + NACOS_LOGIN_API; + HttpEntity> loginRequest = new HttpEntity<>(bodyParams, headers); + ResponseEntity loginResponse; try { - return configService.getConfig(dataId, group, Long.parseLong(properties.getProperty("timeoutMs"))); + loginResponse = restTemplate.postForEntity(loginUrl, loginRequest, String.class); } catch (Exception e) { - log.error("Get Nacos Config error", e); - return "Get Nacos Config error: " + e.getMessage(); + log.error("Nacos login failed.", e); + return ""; } + return JSON.parseObject(loginResponse.getBody()).getString("accessToken"); } } diff --git a/eventmesh-admin-kotlin/src/main/resources/application.yml b/eventmesh-admin-kotlin/src/main/resources/application.yml index 89afc95aa3..aa33e6fe67 100644 --- a/eventmesh-admin-kotlin/src/main/resources/application.yml +++ b/eventmesh-admin-kotlin/src/main/resources/application.yml @@ -36,9 +36,13 @@ eventmesh: type: nacos nacos: addr: 127.0.0.1:8848 - username: nacos - password: nacos -# namespace: # namespace id + authEnabled: false # TODO check auth enabled function + username: + password: + # TODO aliyun nacos auth +# accessKey: +# secretKey: + namespace: # namespace id etcd: addr: # TODO config: