format check on client labels (#11903)

* format check on client labels

* log optimize

* testcase fix
This commit is contained in:
nov.lzf 2024-04-01 14:55:44 +08:00 committed by GitHub
parent 2df335d57e
commit 5fcef225be
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 100 additions and 53 deletions

View File

@ -59,6 +59,8 @@ public class DefaultLabelsCollector implements LabelsCollector {
public Map<String, String> collectLabels(Properties properties) { public Map<String, String> collectLabels(Properties properties) {
//properties //properties
LOGGER.info("default nacos collect properties raw labels: {}",
properties.getProperty(Constants.APP_CONN_LABELS_KEY));
Map<String, String> propertiesLabels = ConnLabelsUtils.parseRawLabels( Map<String, String> propertiesLabels = ConnLabelsUtils.parseRawLabels(
properties.getProperty(Constants.APP_CONN_LABELS_KEY)); properties.getProperty(Constants.APP_CONN_LABELS_KEY));
if (properties.containsKey(Constants.CONFIG_GRAY_LABEL)) { if (properties.containsKey(Constants.CONFIG_GRAY_LABEL)) {
@ -67,6 +69,7 @@ public class DefaultLabelsCollector implements LabelsCollector {
LOGGER.info("default nacos collect properties labels: {}", propertiesLabels); LOGGER.info("default nacos collect properties labels: {}", propertiesLabels);
//jvm //jvm
LOGGER.info("default nacos collect jvm raw labels: {}", System.getProperty(Constants.APP_CONN_LABELS_KEY));
Map<String, String> jvmLabels = ConnLabelsUtils.parseRawLabels( Map<String, String> jvmLabels = ConnLabelsUtils.parseRawLabels(
System.getProperty(Constants.APP_CONN_LABELS_KEY)); System.getProperty(Constants.APP_CONN_LABELS_KEY));
if (System.getProperty(Constants.CONFIG_GRAY_LABEL) != null) { if (System.getProperty(Constants.CONFIG_GRAY_LABEL) != null) {
@ -75,6 +78,8 @@ public class DefaultLabelsCollector implements LabelsCollector {
LOGGER.info("default nacos collect jvm labels: {}", jvmLabels); LOGGER.info("default nacos collect jvm labels: {}", jvmLabels);
//env //env
LOGGER.info("default nacos collect env raw labels: {}",
System.getenv(Constants.APP_CONN_LABELS_KEY.replaceAll(DOT, UNDERSCORE)));
Map<String, String> envLabels = ConnLabelsUtils.parseRawLabels( Map<String, String> envLabels = ConnLabelsUtils.parseRawLabels(
System.getenv(Constants.APP_CONN_LABELS_KEY.replaceAll(DOT, UNDERSCORE))); System.getenv(Constants.APP_CONN_LABELS_KEY.replaceAll(DOT, UNDERSCORE)));
if (System.getenv(Constants.CONFIG_GRAY_LABEL.replaceAll(DOT, UNDERSCORE)) != null) { if (System.getenv(Constants.CONFIG_GRAY_LABEL.replaceAll(DOT, UNDERSCORE)) != null) {

View File

@ -18,6 +18,7 @@ package com.alibaba.nacos.common.labels.impl;
import com.alibaba.nacos.common.labels.LabelsCollector; import com.alibaba.nacos.common.labels.LabelsCollector;
import com.alibaba.nacos.common.labels.LabelsCollectorManager; import com.alibaba.nacos.common.labels.LabelsCollectorManager;
import com.alibaba.nacos.common.utils.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -60,6 +61,11 @@ public class DefaultLabelsCollectorManager implements LabelsCollectorManager {
LOGGER.info("Process LabelsCollector with [name:{}]", labelsCollector.getName()); LOGGER.info("Process LabelsCollector with [name:{}]", labelsCollector.getName());
for (Map.Entry<String, String> entry : labelsCollector.collectLabels(properties).entrySet()) { for (Map.Entry<String, String> entry : labelsCollector.collectLabels(properties).entrySet()) {
if (!checkValidLabel(entry.getKey(), entry.getValue())) {
LOGGER.info(" ignore invalid label with [key:{}, value:{}] of collector [name:{}]", entry.getKey(),
entry.getValue(), labelsCollector.getName());
continue;
}
if (innerAddLabel(labels, entry.getKey(), entry.getValue())) { if (innerAddLabel(labels, entry.getKey(), entry.getValue())) {
LOGGER.info("pick label with [key:{}, value:{}] of collector [name:{}]", entry.getKey(), LOGGER.info("pick label with [key:{}, value:{}] of collector [name:{}]", entry.getKey(),
entry.getValue(), labelsCollector.getName()); entry.getValue(), labelsCollector.getName());
@ -73,6 +79,40 @@ public class DefaultLabelsCollectorManager implements LabelsCollectorManager {
return labels; return labels;
} }
private boolean checkValidLabel(String key, String value) {
return isValid(key) && isValid(value);
}
private static boolean isValid(String param) {
if (StringUtils.isBlank(param)) {
return false;
}
int length = param.length();
if (length > maxLength) {
return false;
}
for (int i = 0; i < length; i++) {
char ch = param.charAt(i);
if (!Character.isLetterOrDigit(ch) && !isValidChar(ch)) {
return false;
}
}
return true;
}
private static char[] validChars = new char[] {'_', '-', '.'};
private static int maxLength = 128;
private static boolean isValidChar(char ch) {
for (char c : validChars) {
if (c == ch) {
return true;
}
}
return false;
}
private ArrayList<LabelsCollector> loadLabelsCollectors() { private ArrayList<LabelsCollector> loadLabelsCollectors() {
ServiceLoader<LabelsCollector> labelsCollectors = ServiceLoader.load(LabelsCollector.class); ServiceLoader<LabelsCollector> labelsCollectors = ServiceLoader.load(LabelsCollector.class);
ArrayList<LabelsCollector> labelsCollectorsList = new ArrayList<>(); ArrayList<LabelsCollector> labelsCollectorsList = new ArrayList<>();

View File

@ -41,22 +41,22 @@ public class ConnLabelsUtils {
public static final int TAG_V2_LABEL_KEY_VALUE_SPLIT_LENGTH = 2; public static final int TAG_V2_LABEL_KEY_VALUE_SPLIT_LENGTH = 2;
public static final int TAG_V1_LABEL_KEY_VALUE_SPLIT_LENGTH = 1;
/** /**
* parse property value to map. * parse property value to map.
* *
* @date 2024/1/29
* @description will get a key-value map from properties, JVM OPTIONS, ENV by order of <tt>properties > JVM OPTIONS > ENV</tt>
* which will use the next level value when the current level value isn't setup.
* <p>eg: if the value of "nacos.app.conn.labels"(properties' key) is "k1=v1,k2=v2"(properties' value), the result will be
* a Map with value{k1=v1,k2=v2}.</p>
* @param properties Properties * @param properties Properties
* @param propertyName which key to get * @param propertyName which key to get
* @return (String)key-(String)value map * @return (String)key-(String)value map
* @date 2024/1/29
* @description will get a key-value map from properties, JVM OPTIONS, ENV by order of <tt>properties > JVM OPTIONS
* > ENV</tt> which will use the next level value when the current level value isn't setup.
* <p>eg: if the value of "nacos.app.conn.labels"(properties' key) is "k1=v1,k2=v2"(properties' value), the result
* will be
* a Map with value{k1=v1,k2=v2}.</p>
*/ */
public static Map<String, String> parsePropertyValue2Map(Properties properties, String propertyName) { public static Map<String, String> parsePropertyValue2Map(Properties properties, String propertyName) {
String rawLabels = properties.getProperty(propertyName, System.getProperty(propertyName, System.getenv(propertyName))); String rawLabels = properties.getProperty(propertyName,
System.getProperty(propertyName, System.getenv(propertyName)));
if (StringUtils.isBlank(rawLabels)) { if (StringUtils.isBlank(rawLabels)) {
LOGGER.info("no value found for property key: {}", propertyName); LOGGER.info("no value found for property key: {}", propertyName);
return new HashMap<>(2); return new HashMap<>(2);
@ -67,10 +67,10 @@ public class ConnLabelsUtils {
/** /**
* parse raw json labels into a key-value map. * parse raw json labels into a key-value map.
* *
* @date 2024/1/29
* @description
* @param rawLabels rawLabels to parse * @param rawLabels rawLabels to parse
* @return map parsed from rawLabels * @return map parsed from rawLabels
* @date 2024/1/29
* @description
*/ */
public static Map<String, String> parseRawLabels(String rawLabels) { public static Map<String, String> parseRawLabels(String rawLabels) {
if (StringUtils.isBlank(rawLabels)) { if (StringUtils.isBlank(rawLabels)) {
@ -78,16 +78,11 @@ public class ConnLabelsUtils {
} }
HashMap<String, String> resultMap = new HashMap<>(2); HashMap<String, String> resultMap = new HashMap<>(2);
try { try {
Arrays.stream(rawLabels.split(LABEL_SPLIT_OPERATOR)) Arrays.stream(rawLabels.split(LABEL_SPLIT_OPERATOR)).filter(Objects::nonNull).map(String::trim)
.filter(Objects::nonNull) .filter(StringUtils::isNotBlank).forEach(label -> {
.map(String::trim)
.filter(StringUtils::isNotBlank)
.forEach(label -> {
String[] kv = label.split(LABEL_EQUALS_OPERATOR); String[] kv = label.split(LABEL_EQUALS_OPERATOR);
if (kv.length == TAG_V2_LABEL_KEY_VALUE_SPLIT_LENGTH) { if (kv.length == TAG_V2_LABEL_KEY_VALUE_SPLIT_LENGTH) {
resultMap.put(kv[0].trim(), kv[1].trim()); resultMap.put(kv[0].trim(), kv[1].trim());
} else if (kv.length == TAG_V1_LABEL_KEY_VALUE_SPLIT_LENGTH) {
resultMap.put(kv[0].trim(), kv[0].trim());
} else { } else {
LOGGER.error("unknown label format: {}", label); LOGGER.error("unknown label format: {}", label);
} }
@ -101,22 +96,30 @@ public class ConnLabelsUtils {
/** /**
* merge two map into one by using the former value when key is duplicated. * merge two map into one by using the former value when key is duplicated.
* *
* @date 2024/1/29
* @description merge two map into one preferring using the first one when key is duplicated
* @param preferredMap preferredMap * @param preferredMap preferredMap
* @param backwardMap backwardMap * @param backwardMap backwardMap
* @date 2024/1/29
* @description merge two map into one preferring using the first one when key is duplicated
*/ */
public static <T, R> Map<T, R> mergeMapByOrder(Map<T, R> preferredMap, Map<T, R> backwardMap) { public static <T, R> Map<T, R> mergeMapByOrder(Map<T, R> preferredMap, Map<T, R> backwardMap) {
if (preferredMap == null || preferredMap.isEmpty()) { if (preferredMap == null || preferredMap.isEmpty()) {
return new HashMap<T, R>(8) { { return new HashMap<T, R>(8) {
putAll(backwardMap); } }; {
putAll(backwardMap);
}
};
} }
if (backwardMap == null || backwardMap.isEmpty()) { if (backwardMap == null || backwardMap.isEmpty()) {
return new HashMap<T, R>(8) { { return new HashMap<T, R>(8) {
putAll(preferredMap); } }; {
putAll(preferredMap);
} }
HashMap<T, R> resultMap = new HashMap<T, R>(8) {{ };
putAll(preferredMap); } }; }
HashMap<T, R> resultMap = new HashMap<T, R>(8) {
{
putAll(preferredMap);
} };
backwardMap.forEach((key, value) -> { backwardMap.forEach((key, value) -> {
if (!resultMap.containsKey(key)) { if (!resultMap.containsKey(key)) {
resultMap.put(key, value); resultMap.put(key, value);
@ -128,17 +131,16 @@ public class ConnLabelsUtils {
/** /**
* add prefix for each key in map. * add prefix for each key in map.
* *
* @date 2024/1/29
* @description add prefix for each key in map
* @param map map to add prefix * @param map map to add prefix
* @param prefix prefix * @param prefix prefix
* @date 2024/1/29
* @description add prefix for each key in map
*/ */
public static <T> Map<String, T> addPrefixForEachKey(Map<String, T> map, String prefix) { public static <T> Map<String, T> addPrefixForEachKey(Map<String, T> map, String prefix) {
if (map == null || map.isEmpty()) { if (map == null || map.isEmpty()) {
return map; return map;
} }
return map.entrySet().stream().filter(Objects::nonNull) return map.entrySet().stream().filter(Objects::nonNull).filter(elem -> !elem.getKey().trim().isEmpty())
.filter(elem -> !elem.getKey().trim().isEmpty())
.collect(Collectors.toMap(elem -> prefix + elem.getKey(), Map.Entry::getValue)); .collect(Collectors.toMap(elem -> prefix + elem.getKey(), Map.Entry::getValue));
} }
} }

View File

@ -39,7 +39,7 @@ public class ConnLabelsUtilsTest {
String rawValue = "k1 = v1, k2 = v2"; String rawValue = "k1 = v1, k2 = v2";
properties.put(property, rawValue); properties.put(property, rawValue);
String property1 = "property2"; String property1 = "property2";
String rawValue1 = "k1, kk2"; String rawValue1 = "k11=v11, kk2";
properties.put(property1, rawValue1); properties.put(property1, rawValue1);
Map<String, String> m = ConnLabelsUtils.parsePropertyValue2Map(properties, property); Map<String, String> m = ConnLabelsUtils.parsePropertyValue2Map(properties, property);
@ -48,15 +48,15 @@ public class ConnLabelsUtilsTest {
assertEquals("v2", m.get("k2")); assertEquals("v2", m.get("k2"));
Map<String, String> m1 = ConnLabelsUtils.parsePropertyValue2Map(properties, property1); Map<String, String> m1 = ConnLabelsUtils.parsePropertyValue2Map(properties, property1);
assertEquals(2, m.size()); assertEquals(1, m1.size());
assertEquals("k1", m1.get("k1")); assertEquals("v11", m1.get("k11"));
assertEquals("kk2", m1.get("kk2")); assertEquals(null, m1.get("kk2"));
m = ConnLabelsUtils.mergeMapByOrder(m, m1); m = ConnLabelsUtils.mergeMapByOrder(m, m1);
assertEquals(3, m.size()); assertEquals(3, m.size());
assertEquals("v1", m.get("k1")); assertEquals("v1", m.get("k1"));
assertEquals("v2", m.get("k2")); assertEquals("v2", m.get("k2"));
assertEquals("kk2", m.get("kk2")); assertEquals("v11", m.get("k11"));
m = ConnLabelsUtils.addPrefixForEachKey(m, "test_prefix"); m = ConnLabelsUtils.addPrefixForEachKey(m, "test_prefix");
assertEquals(3, m.size()); assertEquals(3, m.size());