You are viewing a plain text version of this content. The canonical link for it is here.
Posted to common-commits@hadoop.apache.org by su...@apache.org on 2012/10/27 02:38:49 UTC
svn commit: r1402728 - in /hadoop/common/branches/branch-1: ./
src/core/org/apache/hadoop/conf/ src/core/org/apache/hadoop/http/
src/test/org/apache/hadoop/conf/
Author: suresh
Date: Sat Oct 27 00:38:46 2012
New Revision: 1402728
URL: http://svn.apache.org/viewvc?rev=1402728&view=rev
Log:
HADOOP-8567. Port conf servlet to dump running configuration to branch 1.x. Contributed by Jing Zhao.
Added:
hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/ConfServlet.java
hadoop/common/branches/branch-1/src/test/org/apache/hadoop/conf/TestConfServlet.java
Modified:
hadoop/common/branches/branch-1/CHANGES.txt
hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/Configuration.java
hadoop/common/branches/branch-1/src/core/org/apache/hadoop/http/HttpServer.java
Modified: hadoop/common/branches/branch-1/CHANGES.txt
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/CHANGES.txt?rev=1402728&r1=1402727&r2=1402728&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/CHANGES.txt (original)
+++ hadoop/common/branches/branch-1/CHANGES.txt Sat Oct 27 00:38:46 2012
@@ -104,6 +104,9 @@ Release 1.2.0 - unreleased
HDFS-3062. Print logs outside the namesystem lock invalidateWorkForOneNode
and computeReplicationWorkForBlock. (Jing Zhao via suresh)
+ HADOOP-8567. Port conf servlet to dump running configuration to branch 1.x.
+ (Jing Zhao via suresh)
+
OPTIMIZATIONS
HDFS-2533. Backport: Remove needless synchronization on some FSDataSet
Added: hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/ConfServlet.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/ConfServlet.java?rev=1402728&view=auto
==============================================================================
--- hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/ConfServlet.java (added)
+++ hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/ConfServlet.java Sat Oct 27 00:38:46 2012
@@ -0,0 +1,100 @@
+/**
+ * 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.
+ */
+package org.apache.hadoop.conf;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.hadoop.classification.InterfaceAudience;
+import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.http.HttpServer;
+
+/**
+ * A servlet to print out the running configuration data.
+ */
+@InterfaceAudience.LimitedPrivate({"HDFS", "MapReduce"})
+@InterfaceStability.Unstable
+public class ConfServlet extends HttpServlet {
+ private static final long serialVersionUID = 1L;
+
+ private static final String FORMAT_JSON = "json";
+ private static final String FORMAT_XML = "xml";
+ private static final String FORMAT_PARAM = "format";
+
+ /**
+ * Return the Configuration of the daemon hosting this servlet.
+ * This is populated when the HttpServer starts.
+ */
+ private Configuration getConfFromContext() {
+ Configuration conf = (Configuration)getServletContext().getAttribute(
+ HttpServer.CONF_CONTEXT_ATTRIBUTE);
+ assert conf != null;
+ return conf;
+ }
+
+ @Override
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ String format = request.getParameter(FORMAT_PARAM);
+ if (null == format) {
+ format = FORMAT_XML;
+ }
+
+ if (FORMAT_XML.equals(format)) {
+ response.setContentType("text/xml; charset=utf-8");
+ } else if (FORMAT_JSON.equals(format)) {
+ response.setContentType("application/json; charset=utf-8");
+ }
+
+ Writer out = response.getWriter();
+ try {
+ writeResponse(getConfFromContext(), out, format);
+ } catch (BadFormatException bfe) {
+ response.sendError(HttpServletResponse.SC_BAD_REQUEST, bfe.getMessage());
+ }
+ out.close();
+ }
+
+ /**
+ * Guts of the servlet - extracted for easy testing.
+ */
+ static void writeResponse(Configuration conf, Writer out, String format)
+ throws IOException, BadFormatException {
+ if (FORMAT_JSON.equals(format)) {
+ Configuration.dumpConfiguration(conf, out);
+ } else if (FORMAT_XML.equals(format)) {
+ conf.writeXml(out);
+ } else {
+ throw new BadFormatException("Bad format: " + format);
+ }
+ }
+
+ public static class BadFormatException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public BadFormatException(String msg) {
+ super(msg);
+ }
+ }
+
+}
Modified: hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/Configuration.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/Configuration.java?rev=1402728&r1=1402727&r2=1402728&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/Configuration.java (original)
+++ hadoop/common/branches/branch-1/src/core/org/apache/hadoop/conf/Configuration.java Sat Oct 27 00:38:46 2012
@@ -27,6 +27,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
+import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.net.URL;
@@ -51,6 +52,7 @@ import javax.xml.parsers.DocumentBuilder
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
@@ -65,6 +67,7 @@ import org.apache.hadoop.util.Reflection
import org.apache.hadoop.util.StringUtils;
import org.codehaus.jackson.JsonFactory;
import org.codehaus.jackson.JsonGenerator;
+import org.w3c.dom.Comment;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@@ -171,10 +174,10 @@ public class Configuration implements It
new CopyOnWriteArrayList<String>();
/**
- * Flag to indicate if the storage of resource which updates a key needs
- * to be stored for each key
+ * The value reported as the setting resource when a key is set
+ * by code rather than a file resource.
*/
- private boolean storeResource;
+ static final String UNKNOWN_RESOURCE = "Unknown";
/**
* Stores the mapping of key to the resource which modifies or loads
@@ -223,30 +226,13 @@ public class Configuration implements It
*/
public Configuration(boolean loadDefaults) {
this.loadDefaults = loadDefaults;
+ updatingResource = new HashMap<String, String>();
if (LOG.isDebugEnabled()) {
LOG.debug(StringUtils.stringifyException(new IOException("config()")));
}
synchronized(Configuration.class) {
REGISTRY.put(this, null);
}
- this.storeResource = false;
- }
-
- /**
- * A new configuration with the same settings and additional facility for
- * storage of resource to each key which loads or updates
- * the key most recently
- * @param other the configuration from which to clone settings
- * @param storeResource flag to indicate if the storage of resource to
- * each key is to be stored
- */
- private Configuration(Configuration other, boolean storeResource) {
- this(other);
- this.loadDefaults = other.loadDefaults;
- this.storeResource = storeResource;
- if (storeResource) {
- updatingResource = new HashMap<String, String>();
- }
}
/**
@@ -260,20 +246,23 @@ public class Configuration implements It
LOG.debug(StringUtils.stringifyException
(new IOException("config(config)")));
}
-
- this.resources = (ArrayList)other.resources.clone();
- synchronized(other) {
- if (other.properties != null) {
- this.properties = (Properties)other.properties.clone();
- }
-
- if (other.overlay!=null) {
- this.overlay = (Properties)other.overlay.clone();
- }
- }
-
+
+ this.resources = (ArrayList) other.resources.clone();
+ synchronized (other) {
+ if (other.properties != null) {
+ this.properties = (Properties) other.properties.clone();
+ }
+
+ if (other.overlay != null) {
+ this.overlay = (Properties) other.overlay.clone();
+ }
+
+ this.updatingResource = new HashMap<String, String>(
+ other.updatingResource);
+ }
+
this.finalParameters = new HashSet<String>(other.finalParameters);
- synchronized(Configuration.class) {
+ synchronized (Configuration.class) {
REGISTRY.put(this, null);
}
}
@@ -437,6 +426,7 @@ public class Configuration implements It
public void set(String name, String value) {
getOverlay().setProperty(name, value);
getProps().setProperty(name, value);
+ this.updatingResource.put(name, UNKNOWN_RESOURCE);
}
/**
@@ -1071,10 +1061,8 @@ public class Configuration implements It
loadResources(properties, resources, quietmode);
if (overlay!= null) {
properties.putAll(overlay);
- if (storeResource) {
- for (Map.Entry<Object,Object> item: overlay.entrySet()) {
- updatingResource.put((String) item.getKey(), "Unknown");
- }
+ for (Map.Entry<Object,Object> item: overlay.entrySet()) {
+ updatingResource.put((String) item.getKey(), UNKNOWN_RESOURCE);
}
}
}
@@ -1246,9 +1234,7 @@ public class Configuration implements It
if (value != null) {
if (!finalParameters.contains(attr)) {
properties.setProperty(attr, value);
- if (storeResource) {
- updatingResource.put(attr, name.toString());
- }
+ updatingResource.put(attr, name.toString());
} else if (!value.equals(properties.getProperty(attr))) {
LOG.warn(name+":a attempt to override final parameter: "+attr
+"; Ignoring.");
@@ -1276,12 +1262,22 @@ public class Configuration implements It
}
/**
- * Write out the non-default properties in this configuration to the give
+ * Write out the non-default properties in this configuration to the given
* {@link OutputStream}.
*
* @param out the output stream to write to.
*/
public void writeXml(OutputStream out) throws IOException {
+ writeXml(new OutputStreamWriter(out));
+ }
+
+ /**
+ * Write out the non-default properties in this configuration to the given
+ * {@link Writer}.
+ *
+ * @param out the writer to write to.
+ */
+ public synchronized void writeXml(Writer out) throws IOException {
Properties properties = getProps();
try {
Document doc =
@@ -1300,7 +1296,11 @@ public class Configuration implements It
}
Element propNode = doc.createElement("property");
conf.appendChild(propNode);
-
+ if (updatingResource != null) {
+ Comment commentNode = doc.createComment("Loaded from "
+ + updatingResource.get(name));
+ propNode.appendChild(commentNode);
+ }
Element nameNode = doc.createElement("name");
nameNode.appendChild(doc.createTextNode(name));
propNode.appendChild(nameNode);
@@ -1317,8 +1317,10 @@ public class Configuration implements It
TransformerFactory transFactory = TransformerFactory.newInstance();
Transformer transformer = transFactory.newTransformer();
transformer.transform(source, result);
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (TransformerException te) {
+ throw new IOException(te);
+ } catch (ParserConfigurationException pe) {
+ throw new IOException(pe);
}
}
@@ -1333,26 +1335,26 @@ public class Configuration implements It
* @param out the Writer to write to
* @throws IOException
*/
- public static void dumpConfiguration(Configuration conf,
+ public static void dumpConfiguration(Configuration config,
Writer out) throws IOException {
- Configuration config = new Configuration(conf,true);
- config.reloadConfiguration();
JsonFactory dumpFactory = new JsonFactory();
JsonGenerator dumpGenerator = dumpFactory.createJsonGenerator(out);
dumpGenerator.writeStartObject();
dumpGenerator.writeFieldName("properties");
dumpGenerator.writeStartArray();
dumpGenerator.flush();
- for (Map.Entry<Object,Object> item: config.getProps().entrySet()) {
- dumpGenerator.writeStartObject();
- dumpGenerator.writeStringField("key", (String) item.getKey());
- dumpGenerator.writeStringField("value",
- config.get((String) item.getKey()));
- dumpGenerator.writeBooleanField("isFinal",
- config.finalParameters.contains(item.getKey()));
- dumpGenerator.writeStringField("resource",
- config.updatingResource.get(item.getKey()));
- dumpGenerator.writeEndObject();
+ synchronized (config) {
+ for (Map.Entry<Object,Object> item: config.getProps().entrySet()) {
+ dumpGenerator.writeStartObject();
+ dumpGenerator.writeStringField("key", (String) item.getKey());
+ dumpGenerator.writeStringField("value",
+ config.get((String) item.getKey()));
+ dumpGenerator.writeBooleanField("isFinal",
+ config.finalParameters.contains(item.getKey()));
+ dumpGenerator.writeStringField("resource",
+ config.updatingResource.get(item.getKey()));
+ dumpGenerator.writeEndObject();
+ }
}
dumpGenerator.writeEndArray();
dumpGenerator.writeEndObject();
Modified: hadoop/common/branches/branch-1/src/core/org/apache/hadoop/http/HttpServer.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/core/org/apache/hadoop/http/HttpServer.java?rev=1402728&r1=1402727&r2=1402728&view=diff
==============================================================================
--- hadoop/common/branches/branch-1/src/core/org/apache/hadoop/http/HttpServer.java (original)
+++ hadoop/common/branches/branch-1/src/core/org/apache/hadoop/http/HttpServer.java Sat Oct 27 00:38:46 2012
@@ -42,6 +42,7 @@ import javax.servlet.http.HttpServletRes
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.ConfServlet;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.CommonConfigurationKeys;
import org.apache.hadoop.jmx.JMXJsonServlet;
@@ -85,10 +86,10 @@ public class HttpServer implements Filte
static final String FILTER_INITIALIZER_PROPERTY
= "hadoop.http.filter.initializers";
-
+
// The ServletContext attribute where the daemon Configuration
// gets stored.
- static final String CONF_CONTEXT_ATTRIBUTE = "hadoop.conf";
+ public static final String CONF_CONTEXT_ATTRIBUTE = "hadoop.conf";
static final String ADMINS_ACL = "admins.acl";
public static final String SPNEGO_FILTER = "SpnegoFilter";
public static final String KRB5_FILTER = "krb5Filter";
@@ -273,6 +274,7 @@ public class HttpServer implements Filte
addServlet("stacks", "/stacks", StackServlet.class);
addServlet("logLevel", "/logLevel", LogLevel.Servlet.class);
addServlet("jmx", "/jmx", JMXJsonServlet.class);
+ addServlet("conf", "/conf", ConfServlet.class);
}
public void addContext(Context ctxt, boolean isFiltered)
Added: hadoop/common/branches/branch-1/src/test/org/apache/hadoop/conf/TestConfServlet.java
URL: http://svn.apache.org/viewvc/hadoop/common/branches/branch-1/src/test/org/apache/hadoop/conf/TestConfServlet.java?rev=1402728&view=auto
==============================================================================
--- hadoop/common/branches/branch-1/src/test/org/apache/hadoop/conf/TestConfServlet.java (added)
+++ hadoop/common/branches/branch-1/src/test/org/apache/hadoop/conf/TestConfServlet.java Sat Oct 27 00:38:46 2012
@@ -0,0 +1,113 @@
+/**
+ * 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.
+ */
+package org.apache.hadoop.conf;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.Map;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.junit.Test;
+import org.mortbay.util.ajax.JSON;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+/**
+ * Basic test case that the ConfServlet can write configuration
+ * to its output in XML and JSON format.
+ */
+public class TestConfServlet {
+ private static final String TEST_KEY = "testconfservlet.key";
+ private static final String TEST_VAL = "testval";
+
+ private Configuration getTestConf() {
+ Configuration testConf = new Configuration();
+ testConf.set(TEST_KEY, TEST_VAL);
+ return testConf;
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
+ public void testWriteJson() throws Exception {
+ StringWriter sw = new StringWriter();
+ ConfServlet.writeResponse(getTestConf(), sw, "json");
+ String json = sw.toString();
+ boolean foundSetting = false;
+ Object parsed = JSON.parse(json);
+ Object[] properties = ((Map<String, Object[]>)parsed).get("properties");
+ for (Object o : properties) {
+ Map<String, Object> propertyInfo = (Map<String, Object>)o;
+ String key = (String)propertyInfo.get("key");
+ String val = (String)propertyInfo.get("value");
+ String resource = (String)propertyInfo.get("resource");
+ System.err.println("k: " + key + " v: " + val + " r: " + resource);
+ if (TEST_KEY.equals(key) && TEST_VAL.equals(val)
+ && Configuration.UNKNOWN_RESOURCE.equals(resource)) {
+ foundSetting = true;
+ }
+ }
+ assertTrue(foundSetting);
+ }
+
+ @Test
+ public void testWriteXml() throws Exception {
+ StringWriter sw = new StringWriter();
+ ConfServlet.writeResponse(getTestConf(), sw, "xml");
+ String xml = sw.toString();
+
+ DocumentBuilderFactory docBuilderFactory
+ = DocumentBuilderFactory.newInstance();
+ DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
+ Document doc = builder.parse(new InputSource(new StringReader(xml)));
+ NodeList nameNodes = doc.getElementsByTagName("name");
+ boolean foundSetting = false;
+ for (int i = 0; i < nameNodes.getLength(); i++) {
+ Node nameNode = nameNodes.item(i);
+ String key = nameNode.getTextContent();
+ System.err.println("xml key: " + key);
+ if (TEST_KEY.equals(key)) {
+ foundSetting = true;
+ Element propertyElem = (Element)nameNode.getParentNode();
+ String val = propertyElem.getElementsByTagName("value").item(0).getTextContent();
+ assertEquals(TEST_VAL, val);
+ }
+ }
+ assertTrue(foundSetting);
+ }
+
+ @Test
+ public void testBadFormat() throws Exception {
+ StringWriter sw = new StringWriter();
+ try {
+ ConfServlet.writeResponse(getTestConf(), sw, "not a format");
+ fail("writeResponse with bad format didn't throw!");
+ } catch (ConfServlet.BadFormatException bfe) {
+ // expected
+ }
+ assertEquals("", sw.toString());
+ }
+}
\ No newline at end of file