From 95ad00d901a4a590577998cdd9e65ffb1e84b28a Mon Sep 17 00:00:00 2001 From: wankai123 Date: Thu, 26 Aug 2021 08:53:38 +0800 Subject: [PATCH 1/2] Support k8s configmap grouped dynamic configurations --- CHANGES.md | 1 + ...ConfigmapConfigurationWatcherRegister.java | 25 +- .../ConfigurationConfigmapInformer.java | 42 ++- .../ConfigmapConfigWatcherRegisterTest.java | 59 +++ ...up-dynamic-configmap.example-serviceA.yaml | 349 ++++++++++++++++++ ...up-dynamic-configmap.example-serviceB.yaml | 222 +++++++++++ 6 files changed, 693 insertions(+), 5 deletions(-) create mode 100644 oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml create mode 100644 oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml diff --git a/CHANGES.md b/CHANGES.md index a933392d24bf..5a40b60b5ad8 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -48,6 +48,7 @@ Release Notes. * Support collection type in dynamic configuration core. * Support zookeeper grouped dynamic configurations. * Fix NPE when OAP nodes synchronize events with each other in cluster mode. +* Support k8s configmap grouped dynamic configurations. #### UI diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java index df2c2d0088e5..e770e415a218 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java @@ -19,6 +19,8 @@ package org.apache.skywalking.oap.server.configuration.configmap; import io.kubernetes.client.openapi.models.V1ConfigMap; +import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import lombok.extern.slf4j.Slf4j; @@ -53,8 +55,25 @@ public Optional readConfig(Set keys) { @Override public Optional readGroupConfig(final Set keys) { - // TODO: implement readGroupConfig - return Optional.empty(); - } + GroupConfigTable groupConfigTable = new GroupConfigTable(); + keys.forEach(key -> { + GroupConfigTable.GroupConfigItems groupConfigItems = new GroupConfigTable.GroupConfigItems(key); + groupConfigTable.addGroupConfigItems(groupConfigItems); + List configMapList = informer.groupConfigMap().get(key); + if (configMapList == null) { + return; + } + configMapList.forEach(v1ConfigMap -> { + Map data = v1ConfigMap.getData(); + if (data == null) { + return; + } + v1ConfigMap.getData().forEach((itemName, itemVaule) -> { + groupConfigItems.add(new ConfigTable.ConfigItem(itemName, itemVaule)); + }); + }); + }); + return Optional.of(groupConfigTable); + } } diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java index 84daad34aa4b..b5664a37d3a1 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java @@ -26,8 +26,13 @@ import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapList; +import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.util.Config; import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ExecutorService; @@ -37,7 +42,7 @@ @Slf4j public class ConfigurationConfigmapInformer { - + private final static String LABEL_SW_GROUP_CONFIG_KEY = "sw-group-config-key"; private Lister configMapLister; private SharedInformerFactory factory; @@ -85,7 +90,40 @@ private void doStartConfigMapInformer(final ConfigmapConfigurationSettings setti } public Optional configMap() { - return Optional.ofNullable(configMapLister.list().size() == 1 ? configMapLister.list().get(0) : null); + List singleConfigMapList = new ArrayList<>(); + configMapLister.list().forEach(cf -> { + V1ObjectMeta meta = cf.getMetadata(); + if (meta == null) { + return; + } + + if (meta.getLabels() == null) { + return; + } + + if (meta.getLabels().get(LABEL_SW_GROUP_CONFIG_KEY) == null) { + singleConfigMapList.add(cf); + } + }); + return Optional.ofNullable(singleConfigMapList.size() == 1 ? singleConfigMapList.get(0) : null); } + public Map> groupConfigMap() { + Map> groupConfigMap = new HashMap<>(); + configMapLister.list().forEach(cf -> { + V1ObjectMeta meta = cf.getMetadata(); + if (meta == null) { + return; + } + + if (meta.getLabels() == null) { + return; + } + String groupConfigKey = meta.getLabels().get(LABEL_SW_GROUP_CONFIG_KEY); + if (groupConfigKey != null) { + groupConfigMap.computeIfAbsent(groupConfigKey, list -> new ArrayList<>()).add(cf); + } + }); + return groupConfigMap; + } } diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java b/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java index 46125479de64..d43b452c7bf8 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java @@ -20,6 +20,8 @@ import io.kubernetes.client.openapi.models.V1ConfigMap; import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -27,6 +29,7 @@ import java.util.Optional; import java.util.stream.Collectors; import org.apache.skywalking.oap.server.configuration.api.ConfigTable; +import org.apache.skywalking.oap.server.configuration.api.GroupConfigTable; import org.apache.skywalking.oap.server.library.util.ResourceUtils; import org.junit.Assert; import org.junit.Before; @@ -108,4 +111,60 @@ public void readConfigWhenInformerWork() throws Exception { .collect(Collectors.toList()); Assert.assertEquals(list.size(), 4); } + + @Test + public void readGroupConfigWhenConfigMapDataIsNull() throws Exception { + Map> groupConfigMap = new HashMap<>(); + PowerMockito.doReturn(groupConfigMap).when(informer).groupConfigMap(); + Optional optionalGroupConfigTable = register.readGroupConfig(new HashSet() {{ + add("key1"); + }}); + + Assert.assertTrue(optionalGroupConfigTable.isPresent()); + GroupConfigTable groupConfigTable = optionalGroupConfigTable.get(); + Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "key1"); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 0); + } + + @Test + public void readGroupConfigWhenInformerNotwork() throws Exception { + PowerMockito.doReturn(Optional.empty()).when(informer).configMap(); + Optional optionalGroupConfigTable = register.readGroupConfig(new HashSet() {{ + add("key1"); + }}); + + Assert.assertTrue(optionalGroupConfigTable.isPresent()); + GroupConfigTable groupConfigTable = optionalGroupConfigTable.get(); + Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "key1"); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 0); + } + + @Test + public void readGroupConfigWhenInformerWork() throws Exception { + Reader configmapReaderServiceA = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceA.yaml"); + Reader configmapReaderServiceB = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceB.yaml"); + + Map> configmapMapA = yaml.loadAs(configmapReaderServiceA, Map.class); + Map> configmapMapB = yaml.loadAs(configmapReaderServiceB, Map.class); + + List configMapList = new ArrayList<>(); + configMapList.add(new V1ConfigMap().data(configmapMapA.get("data"))); + configMapList.add(new V1ConfigMap().data(configmapMapB.get("data"))); + + Map> groupConfigMap = new HashMap<>(); + groupConfigMap.put("core.default.endpoint-name-grouping", configMapList); + PowerMockito.doReturn(groupConfigMap).when(informer).groupConfigMap(); + + Optional optionalGroupConfigTable = register.readGroupConfig(new HashSet() {{ + add("core.default.endpoint-name-grouping"); + }}); + Assert.assertTrue(optionalGroupConfigTable.isPresent()); + GroupConfigTable groupConfigTable = optionalGroupConfigTable.get(); + + Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "core.default.endpoint-name-grouping"); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 3); + } } diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml new file mode 100644 index 000000000000..62b5246e2374 --- /dev/null +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml @@ -0,0 +1,349 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +# + +apiVersion: v1 +kind: ConfigMap +metadata: + name: skywalking-dynamic-config + labels: + app: skywalking-config + release: skywalking + sw-group-config-key: core.default.endpoint-name-grouping +data: + customerAPI-v1.yaml: |- + openapi: 3.0.0 + x-sw-service-name: serviceA + info: + description: OpenAPI definition for SkyWalking test. + version: v1 + title: Customer API + + tags: + - name: customer + description: customer + + paths: + /customers: + get: + tags: + - customer + summary: Get all customers list + description: Get all customers list. + operationId: getCustomers + responses: + "200": + description: Success + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Customer" + /customers/{id}: + get: + tags: + - customer + summary: Get customer details + description: Get customer details with the given id. + operationId: getCustomer + parameters: + - name: id + in: path + description: Customer id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/CustomerDetails" + "400": + description: Invalid customer id + post: + tags: + - customer + summary: Update customer details + description: Update customer details with the given id. + operationId: updateCustomer + parameters: + - name: id + in: path + description: Customer id + required: true + schema: + type: integer + format: int64 + - name: name + in: query + description: Customer name + required: true + schema: + type: string + responses: + "200": + description: successful operation + delete: + tags: + - customer + summary: Delete customer details + description: Delete customer details with the given id. + operationId: deleteCustomer + parameters: + - name: id + in: path + description: Customer id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + + /customer/{region}/{country}: + get: + tags: + - customer + summary: Get customers regional + description: Get customers regional with the given id. + operationId: getCustomersRegional + parameters: + - name: region + in: path + description: Customers region + required: true + schema: + type: string + - name: country + in: path + description: Customers country + required: true + schema: + type: string + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/Customer" + "400": + description: Invalid parameters supplied + components: + schemas: + Customer: + type: object + description: Customer id and name + properties: + id: + type: integer + format: int64 + description: Customer id + name: + type: string + description: Customer name + required: + - id + - name + CustomerDetails: + type: object + description: Customer details + properties: + id: + type: integer + format: int64 + description: Customer id + name: + type: string + description: Customer name + description: + type: string + description: Customer description + required: + - id + - name + productAPI-v1.yaml: |- + openapi: 3.0.0 + x-sw-service-name: serviceA + info: + description: OpenAPI definition for SkyWalking test. + version: v1 + title: Product API + + tags: + - name: product + description: product + - name: relatedProducts + description: Related Products + + paths: + /products: + get: + tags: + - product + summary: Get all products list + description: Get all products list. + operationId: getProducts + responses: + "200": + description: Success + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Product" + /products/{id}: + get: + tags: + - product + summary: Get product details + description: Get product details with the given id. + operationId: getProduct + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/ProductDetails" + "400": + description: Invalid product id + post: + tags: + - product + summary: Update product details + description: Update product details with the given id. + operationId: updateProduct + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + - name: name + in: query + description: Product name + required: true + schema: + type: string + responses: + "200": + description: successful operation + delete: + tags: + - product + summary: Delete product details + description: Delete product details with the given id. + operationId: deleteProduct + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + /products/{id}/relatedProducts: + get: + tags: + - relatedProducts + summary: Get related products + description: Get related products with the given product id. + operationId: getRelatedProducts + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/RelatedProducts" + "400": + description: Invalid product id + + components: + schemas: + Product: + type: object + description: Product id and name + properties: + id: + type: integer + format: int64 + description: Product id + name: + type: string + description: Product name + required: + - id + - name + ProductDetails: + type: object + description: Product details + properties: + id: + type: integer + format: int64 + description: Product id + name: + type: string + description: Product name + description: + type: string + description: Product description + required: + - id + - name + RelatedProducts: + type: object + description: Related Products + properties: + id: + type: integer + format: int32 + description: Product id + relatedProducts: + type: array + description: List of related products + items: + $ref: "#/components/schemas/Product" diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml new file mode 100644 index 000000000000..fb7331b04564 --- /dev/null +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml @@ -0,0 +1,222 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. +# The ASF licenses this file to You 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. +# +# + +apiVersion: v1 +kind: ConfigMap +metadata: + name: skywalking-dynamic-config + labels: + app: skywalking-config + release: skywalking + sw-group-config-key: core.default.endpoint-name-grouping +data: + productAPI-v2.yaml: |- + openapi: 3.0.0 + x-sw-service-name: serviceB + info: + description: OpenAPI definition for SkyWalking test. + version: v2 + title: Product API + + tags: + - name: product + description: product + - name: relatedProducts + description: Related Products + + paths: + /products: + get: + tags: + - product + summary: Get all products list + description: Get all products list. + operationId: getProducts + responses: + "200": + description: Success + content: + application/json: + schema: + type: array + items: + $ref: "#/components/schemas/Product" + /products/{region}/{country}: + get: + tags: + - product + summary: Get products regional + description: Get products regional with the given id. + operationId: getProductRegional + parameters: + - name: region + in: path + description: Products region + required: true + schema: + type: string + - name: country + in: path + description: Products country + required: true + schema: + type: string + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/Product" + "400": + description: Invalid parameters supplied + /products/{id}: + get: + tags: + - product + summary: Get product details + description: Get product details with the given id. + operationId: getProduct + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/ProductDetails" + "400": + description: Invalid product id + post: + tags: + - product + summary: Update product details + description: Update product details with the given id. + operationId: updateProduct + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + - name: name + in: query + description: Product name + required: true + schema: + type: string + responses: + "200": + description: successful operation + delete: + tags: + - product + summary: Delete product details + description: Delete product details with the given id. + operationId: deleteProduct + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + /products/{id}/relatedProducts: + get: + tags: + - relatedProducts + summary: Get related products + description: Get related products with the given product id. + operationId: getRelatedProducts + parameters: + - name: id + in: path + description: Product id + required: true + schema: + type: integer + format: int64 + responses: + "200": + description: successful operation + content: + application/json: + schema: + $ref: "#/components/schemas/RelatedProducts" + "400": + description: Invalid product id + + components: + schemas: + Product: + type: object + description: Product id and name + properties: + id: + type: integer + format: int64 + description: Product id + name: + type: string + description: Product name + required: + - id + - name + ProductDetails: + type: object + description: Product details + properties: + id: + type: integer + format: int64 + description: Product id + name: + type: string + description: Product name + description: + type: string + description: Product description + required: + - id + - name + RelatedProducts: + type: object + description: Related Products + properties: + id: + type: integer + format: int32 + description: Product id + relatedProducts: + type: array + description: List of related products + items: + $ref: "#/components/schemas/Product" From ec5d4b7e05a327ae71b360ce6912a883f9c0f903 Mon Sep 17 00:00:00 2001 From: wankai123 Date: Thu, 26 Aug 2021 12:34:56 +0800 Subject: [PATCH 2/2] Support single config read from multiple configmaps, remove label sw-group-config-key --- ...ConfigmapConfigurationWatcherRegister.java | 22 +++---- .../ConfigurationConfigmapInformer.java | 52 ++++------------ .../ConfigmapConfigWatcherRegisterTest.java | 60 ++++++++++--------- .../skywalking-dynamic-configmap.example.yaml | 2 +- ...up-dynamic-configmap.example-serviceA.yaml | 9 ++- ...up-dynamic-configmap.example-serviceB.yaml | 7 +-- 6 files changed, 58 insertions(+), 94 deletions(-) diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java index e770e415a218..7f34e7b6dc23 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigurationWatcherRegister.java @@ -18,8 +18,6 @@ package org.apache.skywalking.oap.server.configuration.configmap; -import io.kubernetes.client.openapi.models.V1ConfigMap; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -42,9 +40,9 @@ public ConfigmapConfigurationWatcherRegister(ConfigmapConfigurationSettings sett @Override public Optional readConfig(Set keys) { final ConfigTable configTable = new ConfigTable(); - Optional v1ConfigMap = informer.configMap(); + Map configMapData = informer.configMapData(); for (final String name : keys) { - final String value = v1ConfigMap.map(V1ConfigMap::getData).map(data -> data.get(name)).orElse(null); + final String value = configMapData.get(name); if (log.isDebugEnabled()) { log.debug("read config: name:{} ,value:{}", name, value); } @@ -56,21 +54,15 @@ public Optional readConfig(Set keys) { @Override public Optional readGroupConfig(final Set keys) { GroupConfigTable groupConfigTable = new GroupConfigTable(); + Map configMapData = informer.configMapData(); keys.forEach(key -> { GroupConfigTable.GroupConfigItems groupConfigItems = new GroupConfigTable.GroupConfigItems(key); groupConfigTable.addGroupConfigItems(groupConfigItems); - List configMapList = informer.groupConfigMap().get(key); - if (configMapList == null) { - return; - } - configMapList.forEach(v1ConfigMap -> { - Map data = v1ConfigMap.getData(); - if (data == null) { - return; + configMapData.forEach((groupItemKey, itemValue) -> { + if (groupItemKey.startsWith(key)) { + String itemName = groupItemKey.replaceFirst(key + ".", ""); + groupConfigItems.add(new ConfigTable.ConfigItem(itemName, itemValue)); } - v1ConfigMap.getData().forEach((itemName, itemVaule) -> { - groupConfigItems.add(new ConfigTable.ConfigItem(itemName, itemVaule)); - }); }); }); diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java index b5664a37d3a1..15061d6719f1 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/main/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigurationConfigmapInformer.java @@ -26,15 +26,11 @@ import io.kubernetes.client.openapi.apis.CoreV1Api; import io.kubernetes.client.openapi.models.V1ConfigMap; import io.kubernetes.client.openapi.models.V1ConfigMapList; -import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.util.Config; import java.io.IOException; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; @@ -42,7 +38,6 @@ @Slf4j public class ConfigurationConfigmapInformer { - private final static String LABEL_SW_GROUP_CONFIG_KEY = "sw-group-config-key"; private Lister configMapLister; private SharedInformerFactory factory; @@ -89,41 +84,18 @@ private void doStartConfigMapInformer(final ConfigmapConfigurationSettings setti configMapLister = new Lister<>(configMapSharedIndexInformer.getIndexer()); } - public Optional configMap() { - List singleConfigMapList = new ArrayList<>(); - configMapLister.list().forEach(cf -> { - V1ObjectMeta meta = cf.getMetadata(); - if (meta == null) { - return; - } - - if (meta.getLabels() == null) { - return; - } - - if (meta.getLabels().get(LABEL_SW_GROUP_CONFIG_KEY) == null) { - singleConfigMapList.add(cf); - } - }); - return Optional.ofNullable(singleConfigMapList.size() == 1 ? singleConfigMapList.get(0) : null); - } - - public Map> groupConfigMap() { - Map> groupConfigMap = new HashMap<>(); - configMapLister.list().forEach(cf -> { - V1ObjectMeta meta = cf.getMetadata(); - if (meta == null) { - return; - } + public Map configMapData() { + Map configMapData = new HashMap<>(); + if (configMapLister != null && configMapLister.list() != null) { + configMapLister.list().forEach(cf -> { + Map data = cf.getData(); + if (data == null) { + return; + } + configMapData.putAll(data); + }); + } - if (meta.getLabels() == null) { - return; - } - String groupConfigKey = meta.getLabels().get(LABEL_SW_GROUP_CONFIG_KEY); - if (groupConfigKey != null) { - groupConfigMap.computeIfAbsent(groupConfigKey, list -> new ArrayList<>()).add(cf); - } - }); - return groupConfigMap; + return configMapData; } } diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java b/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java index d43b452c7bf8..dc8c5b6d8f64 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/java/org/apache/skywalking/oap/server/configuration/configmap/ConfigmapConfigWatcherRegisterTest.java @@ -18,9 +18,8 @@ package org.apache.skywalking.oap.server.configuration.configmap; -import io.kubernetes.client.openapi.models.V1ConfigMap; +import java.io.FileNotFoundException; import java.io.Reader; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -62,8 +61,8 @@ public void prepare() throws IllegalAccessException { @Test public void readConfigWhenConfigMapDataIsNull() throws Exception { - V1ConfigMap v1ConfigMap = new V1ConfigMap(); - PowerMockito.doReturn(Optional.of(v1ConfigMap)).when(informer).configMap(); + Map configMapData = new HashMap<>(); + PowerMockito.doReturn(configMapData).when(informer).configMapData(); Optional optionalConfigTable = register.readConfig(new HashSet() {{ add("key1"); }}); @@ -77,7 +76,7 @@ public void readConfigWhenConfigMapDataIsNull() throws Exception { @Test public void readConfigWhenInformerNotwork() throws Exception { - PowerMockito.doReturn(Optional.empty()).when(informer).configMap(); + PowerMockito.doReturn(new HashMap<>()).when(informer).configMapData(); Optional optionalConfigTable = register.readConfig(new HashSet() {{ add("key1"); }}); @@ -91,17 +90,15 @@ public void readConfigWhenInformerNotwork() throws Exception { @Test public void readConfigWhenInformerWork() throws Exception { - Reader configmapReader = ResourceUtils.read("skywalking-dynamic-configmap.example.yaml"); - Map> configmapMap = yaml.loadAs(configmapReader, Map.class); - V1ConfigMap v1ConfigMap = new V1ConfigMap(); - v1ConfigMap.data(configmapMap.get("data")); - PowerMockito.doReturn(Optional.of(v1ConfigMap)).when(informer).configMap(); + Map configMapData = this.readMockConfigMapData(); + PowerMockito.doReturn(configMapData).when(informer).configMapData(); Optional optionalConfigTable = register.readConfig(new HashSet() {{ add("receiver-trace.default.slowDBAccessThreshold"); add("alarm.default.alarm-settings"); add("core.default.apdexThreshold"); add("receiver-trace.default.uninstrumentedGateways"); }}); + Assert.assertTrue(optionalConfigTable.isPresent()); ConfigTable configTable = optionalConfigTable.get(); @@ -114,8 +111,8 @@ public void readConfigWhenInformerWork() throws Exception { @Test public void readGroupConfigWhenConfigMapDataIsNull() throws Exception { - Map> groupConfigMap = new HashMap<>(); - PowerMockito.doReturn(groupConfigMap).when(informer).groupConfigMap(); + Map configMapData = new HashMap<>(); + PowerMockito.doReturn(configMapData).when(informer).configMapData(); Optional optionalGroupConfigTable = register.readGroupConfig(new HashSet() {{ add("key1"); }}); @@ -129,7 +126,7 @@ public void readGroupConfigWhenConfigMapDataIsNull() throws Exception { @Test public void readGroupConfigWhenInformerNotwork() throws Exception { - PowerMockito.doReturn(Optional.empty()).when(informer).configMap(); + PowerMockito.doReturn(new HashMap<>()).when(informer).configMapData(); Optional optionalGroupConfigTable = register.readGroupConfig(new HashSet() {{ add("key1"); }}); @@ -143,28 +140,33 @@ public void readGroupConfigWhenInformerNotwork() throws Exception { @Test public void readGroupConfigWhenInformerWork() throws Exception { - Reader configmapReaderServiceA = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceA.yaml"); - Reader configmapReaderServiceB = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceB.yaml"); - - Map> configmapMapA = yaml.loadAs(configmapReaderServiceA, Map.class); - Map> configmapMapB = yaml.loadAs(configmapReaderServiceB, Map.class); - - List configMapList = new ArrayList<>(); - configMapList.add(new V1ConfigMap().data(configmapMapA.get("data"))); - configMapList.add(new V1ConfigMap().data(configmapMapB.get("data"))); - - Map> groupConfigMap = new HashMap<>(); - groupConfigMap.put("core.default.endpoint-name-grouping", configMapList); - PowerMockito.doReturn(groupConfigMap).when(informer).groupConfigMap(); - + Map configMapData = this.readMockConfigMapData(); + PowerMockito.doReturn(configMapData).when(informer).configMapData(); Optional optionalGroupConfigTable = register.readGroupConfig(new HashSet() {{ - add("core.default.endpoint-name-grouping"); + add("core.default.endpoint-name-grouping-openapi"); }}); + Assert.assertTrue(optionalGroupConfigTable.isPresent()); GroupConfigTable groupConfigTable = optionalGroupConfigTable.get(); Assert.assertEquals(groupConfigTable.getGroupItems().size(), 1); - Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "core.default.endpoint-name-grouping"); + Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getName(), "core.default.endpoint-name-grouping-openapi"); Assert.assertEquals(groupConfigTable.getGroupItems().get(0).getItems().size(), 3); } + + private Map readMockConfigMapData() throws FileNotFoundException { + Reader configmapReader1 = ResourceUtils.read("skywalking-dynamic-configmap.example.yaml"); + Reader configmapReader2 = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceA.yaml"); + Reader configmapReader3 = ResourceUtils.read("skywalking-group-dynamic-configmap.example-serviceB.yaml"); + Map> configmapMap1 = yaml.loadAs(configmapReader1, Map.class); + Map> configmapMap2 = yaml.loadAs(configmapReader2, Map.class); + Map> configmapMap3 = yaml.loadAs(configmapReader3, Map.class); + + Map configMapData = new HashMap<>(); + configMapData.putAll(configmapMap1.get("data")); + configMapData.putAll(configmapMap2.get("data")); + configMapData.putAll(configmapMap3.get("data")); + + return configMapData; + } } diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-dynamic-configmap.example.yaml b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-dynamic-configmap.example.yaml index 18a07de2b93d..d715988ebe44 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-dynamic-configmap.example.yaml +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-dynamic-configmap.example.yaml @@ -21,7 +21,7 @@ kind: ConfigMap metadata: name: skywalking-dynamic-config labels: - app: skywalking-alarm + app: collector release: skywalking data: receiver-trace.default.slowDBAccessThreshold: default:200,mongodb:50 diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml index 62b5246e2374..81ac5ed3e219 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceA.yaml @@ -19,13 +19,12 @@ apiVersion: v1 kind: ConfigMap metadata: - name: skywalking-dynamic-config + name: skywalking-dynamic-config2 labels: - app: skywalking-config + app: collector release: skywalking - sw-group-config-key: core.default.endpoint-name-grouping data: - customerAPI-v1.yaml: |- + core.default.endpoint-name-grouping-openapi.customerAPI-v1.yaml: |- openapi: 3.0.0 x-sw-service-name: serviceA info: @@ -181,7 +180,7 @@ data: required: - id - name - productAPI-v1.yaml: |- + core.default.endpoint-name-grouping-openapi.productAPI-v1.yaml: |- openapi: 3.0.0 x-sw-service-name: serviceA info: diff --git a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml index fb7331b04564..0db85f1aa462 100644 --- a/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml +++ b/oap-server/server-configuration/configuration-k8s-configmap/src/test/resources/skywalking-group-dynamic-configmap.example-serviceB.yaml @@ -19,13 +19,12 @@ apiVersion: v1 kind: ConfigMap metadata: - name: skywalking-dynamic-config + name: skywalking-dynamic-config3 labels: - app: skywalking-config + app: collector release: skywalking - sw-group-config-key: core.default.endpoint-name-grouping data: - productAPI-v2.yaml: |- + core.default.endpoint-name-grouping-openapi.productAPI-v2.yaml: |- openapi: 3.0.0 x-sw-service-name: serviceB info: