From f986916acf20dc6b0f6b98e175ac170ec127bd0b Mon Sep 17 00:00:00 2001 From: Joey777210 <53630996+Joey777210@users.noreply.github.com> Date: Mon, 17 Jul 2023 11:20:07 +0800 Subject: [PATCH] [ISSUE #10662]Prometheus-sd add namespace and service api (#10663) * add apis * add tests * fix checkstyle * param namespace to namespaceId * namespace to namespaceId * fix test case * fix test case --- .../nacos/prometheus/api/ApiConstants.java | 4 + .../conf/PrometheusSecurityConfiguration.java | 4 + .../controller/PrometheusController.java | 84 ++++++++++++++----- .../prometheus/utils/PrometheusUtils.java | 56 +++++++++++++ .../controller/PrometheusControllerTest.java | 25 ++++++ 5 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 prometheus/src/main/java/com/alibaba/nacos/prometheus/utils/PrometheusUtils.java diff --git a/prometheus/src/main/java/com/alibaba/nacos/prometheus/api/ApiConstants.java b/prometheus/src/main/java/com/alibaba/nacos/prometheus/api/ApiConstants.java index c4e916780f3..21864ced96e 100644 --- a/prometheus/src/main/java/com/alibaba/nacos/prometheus/api/ApiConstants.java +++ b/prometheus/src/main/java/com/alibaba/nacos/prometheus/api/ApiConstants.java @@ -24,5 +24,9 @@ public class ApiConstants { public static final String PROMETHEUS_CONTROLLER_PATH = "/prometheus"; + + public static final String PROMETHEUS_CONTROLLER_NAMESPACE_PATH = "/prometheus/namespaceId/{namespaceId}"; + + public static final String PROMETHEUS_CONTROLLER_SERVICE_PATH = "/prometheus/namespaceId/{namespaceId}/service/{service}"; } diff --git a/prometheus/src/main/java/com/alibaba/nacos/prometheus/conf/PrometheusSecurityConfiguration.java b/prometheus/src/main/java/com/alibaba/nacos/prometheus/conf/PrometheusSecurityConfiguration.java index 87488b71288..991c966301f 100644 --- a/prometheus/src/main/java/com/alibaba/nacos/prometheus/conf/PrometheusSecurityConfiguration.java +++ b/prometheus/src/main/java/com/alibaba/nacos/prometheus/conf/PrometheusSecurityConfiguration.java @@ -21,7 +21,9 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; +import static com.alibaba.nacos.prometheus.api.ApiConstants.PROMETHEUS_CONTROLLER_NAMESPACE_PATH; import static com.alibaba.nacos.prometheus.api.ApiConstants.PROMETHEUS_CONTROLLER_PATH; +import static com.alibaba.nacos.prometheus.api.ApiConstants.PROMETHEUS_CONTROLLER_SERVICE_PATH; /** @@ -36,5 +38,7 @@ public class PrometheusSecurityConfiguration extends WebSecurityConfigurerAdapte @Override public void configure(WebSecurity web) throws Exception { web.ignoring().mvcMatchers(PROMETHEUS_CONTROLLER_PATH); + web.ignoring().mvcMatchers(PROMETHEUS_CONTROLLER_NAMESPACE_PATH); + web.ignoring().mvcMatchers(PROMETHEUS_CONTROLLER_SERVICE_PATH); } } diff --git a/prometheus/src/main/java/com/alibaba/nacos/prometheus/controller/PrometheusController.java b/prometheus/src/main/java/com/alibaba/nacos/prometheus/controller/PrometheusController.java index 954fc6433c2..19d197ed8b8 100644 --- a/prometheus/src/main/java/com/alibaba/nacos/prometheus/controller/PrometheusController.java +++ b/prometheus/src/main/java/com/alibaba/nacos/prometheus/controller/PrometheusController.java @@ -23,20 +23,19 @@ import com.alibaba.nacos.naming.core.v2.ServiceManager; import com.alibaba.nacos.naming.core.v2.pojo.Service; import com.alibaba.nacos.prometheus.api.ApiConstants; +import com.alibaba.nacos.prometheus.utils.PrometheusUtils; import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Set; -import static java.util.stream.Collectors.groupingBy; /** * Support Prometheus SD Controller. @@ -73,26 +72,73 @@ public ResponseEntity metric() throws NacosException { List instances = instanceServiceV2.listAllInstances(namespace, service.getGroupedServiceName()); - for (Instance instance : instances) { - targetSet.add(instance); - } + targetSet.addAll(instances); } } - Map> groupingInsMap = targetSet.stream().collect(groupingBy(Instance::getClusterName)); - groupingInsMap.forEach((key, value) -> { - ObjectNode jsonNode = JacksonUtils.createEmptyJsonNode(); - ArrayNode targetsNode = JacksonUtils.createEmptyArrayNode(); - ObjectNode labelNode = JacksonUtils.createEmptyJsonNode(); - value.forEach(e -> { - targetsNode.add(e.getIp() + ":" + e.getPort()); - }); - labelNode.put("__meta_clusterName", key); - jsonNode.replace("targets", targetsNode); - jsonNode.replace("labels", labelNode); - arrayNode.add(jsonNode); + + PrometheusUtils.assembleArrayNodes(targetSet, arrayNode); + return ResponseEntity.ok().body(arrayNode.toString()); + } + + + /** + * Get service instances from designated namespace. + * + * @throws NacosException NacosException. + */ + @GetMapping(value = ApiConstants.PROMETHEUS_CONTROLLER_NAMESPACE_PATH, produces = "application/json; charset=UTF-8") + public ResponseEntity metricNamespace(@PathVariable("namespaceId") String namespaceId) throws NacosException { + ArrayNode arrayNode = JacksonUtils.createEmptyArrayNode(); + Set targetSet = new HashSet<>(); + Set allNamespaces = serviceManager.getAllNamespaces(); + if (!allNamespaces.contains(namespaceId)) { + return ResponseEntity.ok().body(arrayNode.toString()); + } + + Set singletons = serviceManager.getSingletons(namespaceId); + for (Service service : singletons) { + + List instances = instanceServiceV2.listAllInstances(namespaceId, + service.getGroupedServiceName()); + + targetSet.addAll(instances); + + } + + PrometheusUtils.assembleArrayNodes(targetSet, arrayNode); + return ResponseEntity.ok().body(arrayNode.toString()); + } + + /** + * Get service instances from designated namespace and service. + * + * @throws NacosException NacosException. + */ + @GetMapping(value = ApiConstants.PROMETHEUS_CONTROLLER_SERVICE_PATH, produces = "application/json; charset=UTF-8") + public ResponseEntity metricNamespaceService(@PathVariable("namespaceId") String namespaceId, + @PathVariable("service") String service) throws NacosException { + ArrayNode arrayNode = JacksonUtils.createEmptyArrayNode(); + Set targetSet = new HashSet<>(); + Set allNamespaces = serviceManager.getAllNamespaces(); + if (!allNamespaces.contains(namespaceId)) { + return ResponseEntity.ok().body(arrayNode.toString()); + } + + Set singletons = serviceManager.getSingletons(namespaceId); + for (Service existService : singletons) { + if (!existService.getName().equals(service)) { + continue; + } + List instances = instanceServiceV2.listAllInstances(namespaceId, + existService.getGroupedServiceName()); + + targetSet.addAll(instances); - }); + } + + PrometheusUtils.assembleArrayNodes(targetSet, arrayNode); + return ResponseEntity.ok().body(arrayNode.toString()); } } diff --git a/prometheus/src/main/java/com/alibaba/nacos/prometheus/utils/PrometheusUtils.java b/prometheus/src/main/java/com/alibaba/nacos/prometheus/utils/PrometheusUtils.java new file mode 100644 index 00000000000..9fd377af57e --- /dev/null +++ b/prometheus/src/main/java/com/alibaba/nacos/prometheus/utils/PrometheusUtils.java @@ -0,0 +1,56 @@ +/* + * Copyright 1999-2018 Alibaba Group Holding Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.alibaba.nacos.prometheus.utils; + +import com.alibaba.nacos.api.naming.pojo.Instance; +import com.alibaba.nacos.common.utils.JacksonUtils; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static java.util.stream.Collectors.groupingBy; + +/** + * prometheus common utils. + * + * @author Joey777210 + */ +public class PrometheusUtils { + + /** + * Assemble arrayNodes for prometheus sd api. + * + */ + public static void assembleArrayNodes(Set targetSet, ArrayNode arrayNode) { + Map> groupingInsMap = targetSet.stream().collect(groupingBy(Instance::getClusterName)); + groupingInsMap.forEach((key, value) -> { + ObjectNode jsonNode = JacksonUtils.createEmptyJsonNode(); + ArrayNode targetsNode = JacksonUtils.createEmptyArrayNode(); + ObjectNode labelNode = JacksonUtils.createEmptyJsonNode(); + value.forEach(e -> { + targetsNode.add(e.getIp() + ":" + e.getPort()); + }); + labelNode.put("__meta_clusterName", key); + jsonNode.replace("targets", targetsNode); + jsonNode.replace("labels", labelNode); + arrayNode.add(jsonNode); + }); + } +} diff --git a/prometheus/src/test/java/com/alibaba/nacos/prometheus/controller/PrometheusControllerTest.java b/prometheus/src/test/java/com/alibaba/nacos/prometheus/controller/PrometheusControllerTest.java index 8086f1416da..b321c9ab913 100644 --- a/prometheus/src/test/java/com/alibaba/nacos/prometheus/controller/PrometheusControllerTest.java +++ b/prometheus/src/test/java/com/alibaba/nacos/prometheus/controller/PrometheusControllerTest.java @@ -103,4 +103,29 @@ public void testMetric() throws Exception { assertEquals(testInstanceList.size(), JacksonUtils.toObj(response.getContentAsString()).size()); } + @Test + public void testMetricNamespace() throws Exception { + when(instanceServiceV2.listAllInstances(nameSpace, NamingUtils.getGroupedName(name, group))).thenReturn( + testInstanceList); + String prometheusNamespacePath = ApiConstants.PROMETHEUS_CONTROLLER_NAMESPACE_PATH.replace("{namespaceId}", + nameSpace); + MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(prometheusNamespacePath); + MockHttpServletResponse response = mockMvc.perform(builder).andReturn().getResponse(); + Assert.assertEquals(200, response.getStatus()); + assertEquals(testInstanceList.size(), JacksonUtils.toObj(response.getContentAsString()).size()); + } + + @Test + public void testMetricNamespaceService() throws Exception { + when(instanceServiceV2.listAllInstances(nameSpace, NamingUtils.getGroupedName(name, group))).thenReturn( + testInstanceList); + String promethesuNamespaceServicePath = ApiConstants.PROMETHEUS_CONTROLLER_SERVICE_PATH.replace("{namespaceId}", + nameSpace); + promethesuNamespaceServicePath = promethesuNamespaceServicePath.replace("{service}", service.getName()); + MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get(promethesuNamespaceServicePath); + MockHttpServletResponse response = mockMvc.perform(builder).andReturn().getResponse(); + Assert.assertEquals(200, response.getStatus()); + assertEquals(testInstanceList.size(), JacksonUtils.toObj(response.getContentAsString()).size()); + } + }