This is an automated email from the ASF dual-hosted git repository.
adoroszlai pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new 39e4673787c HDDS-499. Display descriptions for properties on the
configuration page (#9152)
39e4673787c is described below
commit 39e4673787cecfbae7b4c0b160b4dc28c5a2f341
Author: Rishabh Patel <[email protected]>
AuthorDate: Wed Nov 19 05:47:48 2025 -0800
HDDS-499. Display descriptions for properties on the configuration page
(#9152)
---
.../hadoop/hdds/conf/OzoneConfiguration.java | 30 +++++--
.../apache/hadoop/hdds/conf/HddsConfServlet.java | 98 +++++++++++++++++++++-
.../src/main/resources/webapps/static/ozone.js | 10 ++-
.../resources/webapps/static/templates/config.html | 4 +-
4 files changed, 126 insertions(+), 16 deletions(-)
diff --git
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
index f863f3a303e..fc09a5a5933 100644
---
a/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
+++
b/hadoop-hdds/common/src/main/java/org/apache/hadoop/hdds/conf/OzoneConfiguration.java
@@ -209,11 +209,16 @@ public boolean equals(Object obj) {
}
}
- /** Add default resources. */
- public static void activate() {
- // core-default and core-site are added by parent class
- addDefaultResource("hdfs-default.xml");
- addDefaultResource("hdfs-site.xml");
+ public static List<String> getConfigurationResourceFiles() {
+ List<String> resourceFiles = new ArrayList<>();
+
+ // even though core-default and core-site are added by the parent
Configuration class,
+ // we add it here for them to be a part of the resourceFiles list.
+ // addDefaultResource is idempotent so any duplicate items in this list
will be handled accordingly
+ resourceFiles.add("hdfs-default.xml");
+ resourceFiles.add("hdfs-site.xml");
+ resourceFiles.add("core-default.xml");
+ resourceFiles.add("core-site.xml");
// Modules with @Config annotations. If new one is introduced, add it to
this list.
String[] modules = new String[] {
@@ -228,12 +233,21 @@ public static void activate() {
"ozone-recon",
};
for (String module : modules) {
- addDefaultResource(module + "-default.xml");
+ resourceFiles.add(module + "-default.xml");
}
// Non-generated configs
- addDefaultResource("ozone-default.xml");
- addDefaultResource("ozone-site.xml");
+ resourceFiles.add("ozone-default.xml");
+ resourceFiles.add("ozone-site.xml");
+
+ return resourceFiles;
+ }
+
+ /** Add default resources. */
+ public static void activate() {
+ for (String resourceFile : getConfigurationResourceFiles()) {
+ addDefaultResource(resourceFile);
+ }
}
/**
diff --git
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
index 066735a0258..719ce052276 100644
---
a/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
+++
b/hadoop-hdds/framework/src/main/java/org/apache/hadoop/hdds/conf/HddsConfServlet.java
@@ -17,8 +17,12 @@
package org.apache.hadoop.hdds.conf;
+import static
org.apache.hadoop.hdds.conf.OzoneConfiguration.getConfigurationResourceFiles;
+
import java.io.IOException;
+import java.io.InputStream;
import java.io.Writer;
+import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@@ -26,14 +30,22 @@
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.ConfServlet.BadFormatException;
import org.apache.hadoop.hdds.annotation.InterfaceAudience;
import org.apache.hadoop.hdds.annotation.InterfaceStability;
import org.apache.hadoop.hdds.server.JsonUtils;
import org.apache.hadoop.hdds.server.http.HttpServer2;
import org.apache.hadoop.hdds.utils.HttpServletUtils;
+import org.apache.hadoop.util.XMLUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
/**
* A servlet to print out the running configuration data.
@@ -123,12 +135,25 @@ private void processConfigTagRequest(HttpServletRequest
request, String cmd, Htt
throw new IllegalArgumentException("The tags parameter should be set" +
" when using the getPropertyByTag command.");
}
- Map<String, Properties> propMap = new HashMap<>();
+
+ Map<String, String> descriptionMap = buildDescriptionMap(config);
+ Map<String, Map<String, OzoneConfiguration.Property>> propMap = new
HashMap<>();
for (String tag : tags.split(",")) {
if (config.isPropertyTag(tag)) {
Properties properties = config.getAllPropertiesByTag(tag);
- propMap.put(tag, properties);
+ Map<String, OzoneConfiguration.Property> metadataMap = new
HashMap<>();
+
+ for (String propName : properties.stringPropertyNames()) {
+ String value = properties.getProperty(propName);
+ String description = descriptionMap.getOrDefault(propName, "");
+ OzoneConfiguration.Property property = new
OzoneConfiguration.Property();
+ property.setName(propName);
+ property.setValue(value);
+ property.setDescription(description);
+ metadataMap.put(propName, property);
+ }
+ propMap.put(tag, metadataMap);
}
}
out.write(JsonUtils.toJsonString(propMap));
@@ -138,6 +163,75 @@ private void processConfigTagRequest(HttpServletRequest
request, String cmd, Htt
}
}
+ /**
+ * Build a map of property names to descriptions by reading from
configuration resources.
+ * @param config the OzoneConfiguration to extract descriptions from
+ * @return map of property name to description
+ */
+ private Map<String, String> buildDescriptionMap(OzoneConfiguration config) {
+ Map<String, String> descriptionMap = new HashMap<>();
+
+ try {
+ DocumentBuilderFactory factory =
XMLUtils.newSecureDocumentBuilderFactory();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+
+ for (String resourceName : getConfigurationResourceFiles()) {
+ URL resourceUrl = config.getResource(resourceName);
+ if (resourceUrl != null) {
+ parseXmlDescriptions(builder, resourceUrl, descriptionMap);
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Failed to parse XML resource files", e);
+ }
+
+ return descriptionMap;
+ }
+
+ /**
+ * Parse XML configuration file and extract property descriptions using DOM
parser.
+ * @param builder The XML parser
+ * @param resourceUrl URL of the XML resource to parse
+ * @param descriptionMap map to populate with property name -> description
mappings
+ */
+ private void parseXmlDescriptions(DocumentBuilder builder, URL resourceUrl,
Map<String, String> descriptionMap) {
+ try (InputStream inputStream = resourceUrl.openStream()) {
+ Document doc = builder.parse(inputStream);
+ NodeList propertyNodes = doc.getElementsByTagName("property");
+
+ for (int i = 0; i < propertyNodes.getLength(); i++) {
+ Node propertyNode = propertyNodes.item(i);
+ if (propertyNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element propertyElement = (Element) propertyNode;
+
+ String name = getTextContent(propertyElement, "name");
+ String description = getTextContent(propertyElement, "description");
+
+ if (name != null && !StringUtils.isBlank(description)) {
+ descriptionMap.put(name, description.trim());
+ }
+ }
+ }
+ } catch (Exception e) {
+ LOG.error("Failed to parse XML from resource: {}", resourceUrl, e);
+ }
+ }
+
+ /**
+ * Get text content of a child element by tag name.
+ * @param parent parent element
+ * @param tagName tag name of child element
+ * @return text content of the child element, or null if not found
+ */
+ private String getTextContent(Element parent, String tagName) {
+ NodeList nodeList = parent.getElementsByTagName(tagName);
+ if (nodeList.getLength() > 0) {
+ Node node = nodeList.item(0);
+ return node.getTextContent();
+ }
+ return null;
+ }
+
private static OzoneConfiguration getOzoneConfig() {
return OZONE_CONFIG;
}
diff --git a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
index 7bb93106284..aac641e625e 100644
--- a/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
+++ b/hadoop-hdds/framework/src/main/resources/webapps/static/ozone.js
@@ -296,13 +296,15 @@
for (var idx in srcObj) {
//console.log("Adding keys for "+idx)
for (var key in srcObj[idx]) {
-
+ var propMetadata = srcObj[idx][key];
+
if (ctrl.keyTagMap.hasOwnProperty(key)) {
ctrl.keyTagMap[key]['tag'].push(idx);
} else {
var newProp = {};
- newProp['name'] = key;
- newProp['value'] = srcObj[idx][key];
+ newProp['name'] = propMetadata.name || key;
+ newProp['value'] = propMetadata.value;
+ newProp['description'] = propMetadata.description || '';
newProp['tag'] = [];
newProp['tag'].push(idx);
ctrl.keyTagMap[key] = newProp;
@@ -392,4 +394,4 @@
}
});
-})();
\ No newline at end of file
+})();
diff --git
a/hadoop-hdds/framework/src/main/resources/webapps/static/templates/config.html
b/hadoop-hdds/framework/src/main/resources/webapps/static/templates/config.html
index b52f6533fc9..9d3bc90915d 100644
---
a/hadoop-hdds/framework/src/main/resources/webapps/static/templates/config.html
+++
b/hadoop-hdds/framework/src/main/resources/webapps/static/templates/config.html
@@ -81,8 +81,8 @@
<tbody>
<tr
ng-repeat="config in $ctrl.configs | filter:search |
orderBy:$ctrl.propertyName:$ctrl.reverse">
- <td style="word-wrap: break-word;">{{config.name}}</td>
- <td style="word-wrap: break-word;">{{config.value}}</td>
+ <td style="word-wrap: break-word; font-family:
monospace;">{{config.name}}</td>
+ <td style="word-wrap: break-word; font-family:
monospace;">{{config.value}}</td>
<td style="word-wrap: break-word;">{{config.description}}</td>
</tr>
</tbody>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]