HDFS-5279. Merging change r1528308 from trunk to branch-2.

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/branches/branch-2@1528310 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Chris Nauroth 2013-10-02 05:37:21 +00:00
parent 09d2301b63
commit a5d9aaad12
6 changed files with 125 additions and 27 deletions

View File

@ -144,6 +144,9 @@ Release 2.1.2 - UNRELEASED
HDFS-5255. Distcp job fails with hsftp when https is enabled in insecure HDFS-5255. Distcp job fails with hsftp when https is enabled in insecure
cluster. (Arpit Agarwal) cluster. (Arpit Agarwal)
HDFS-5279. Guard against NullPointerException in NameNode JSP pages before
initialization of FSNamesystem. (cnauroth)
Release 2.1.1-beta - 2013-09-23 Release 2.1.1-beta - 2013-09-23
INCOMPATIBLE CHANGES INCOMPATIBLE CHANGES

View File

@ -30,6 +30,7 @@ import java.net.URLEncoder;
import java.security.PrivilegedExceptionAction; import java.security.PrivilegedExceptionAction;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -209,6 +210,9 @@ class NamenodeJspHelper {
static void generateSnapshotReport(JspWriter out, FSNamesystem fsn) static void generateSnapshotReport(JspWriter out, FSNamesystem fsn)
throws IOException { throws IOException {
if (fsn == null) {
return;
}
out.println("<div id=\"snapshotstats\"><div class=\"dfstable\">" out.println("<div id=\"snapshotstats\"><div class=\"dfstable\">"
+ "<table class=\"storage\" title=\"Snapshot Summary\">\n" + "<table class=\"storage\" title=\"Snapshot Summary\">\n"
+ "<thead><tr><td><b>Snapshottable directories</b></td>" + "<thead><tr><td><b>Snapshottable directories</b></td>"
@ -651,7 +655,8 @@ class NamenodeJspHelper {
.getAttribute(JspHelper.CURRENT_CONF); .getAttribute(JspHelper.CURRENT_CONF);
// We can't redirect if there isn't a DN to redirect to. // We can't redirect if there isn't a DN to redirect to.
// Lets instead show a proper error message. // Lets instead show a proper error message.
if (nn.getNamesystem().getNumLiveDataNodes() < 1) { FSNamesystem fsn = nn.getNamesystem();
if (fsn == null || fsn.getNumLiveDataNodes() < 1) {
throw new IOException("Can't browse the DFS since there are no " + throw new IOException("Can't browse the DFS since there are no " +
"live nodes available to redirect to."); "live nodes available to redirect to.");
} }
@ -687,6 +692,20 @@ class NamenodeJspHelper {
resp.sendRedirect(redirectLocation); resp.sendRedirect(redirectLocation);
} }
/**
* Returns a descriptive label for the running NameNode. If the NameNode has
* initialized to the point of running its RPC server, then this label consists
* of the host and port of the RPC server. Otherwise, the label is a message
* stating that the NameNode is still initializing.
*
* @param nn NameNode to describe
* @return String NameNode label
*/
static String getNameNodeLabel(NameNode nn) {
return nn.getRpcServer() != null ? nn.getNameNodeAddressHostPortString() :
"initializing";
}
static class NodeListJsp { static class NodeListJsp {
private int rowNum = 0; private int rowNum = 0;
@ -841,6 +860,9 @@ class NamenodeJspHelper {
HttpServletRequest request) throws IOException { HttpServletRequest request) throws IOException {
final NameNode nn = NameNodeHttpServer.getNameNodeFromContext(context); final NameNode nn = NameNodeHttpServer.getNameNodeFromContext(context);
final FSNamesystem ns = nn.getNamesystem(); final FSNamesystem ns = nn.getNamesystem();
if (ns == null) {
return;
}
final DatanodeManager dm = ns.getBlockManager().getDatanodeManager(); final DatanodeManager dm = ns.getBlockManager().getDatanodeManager();
final List<DatanodeDescriptor> live = new ArrayList<DatanodeDescriptor>(); final List<DatanodeDescriptor> live = new ArrayList<DatanodeDescriptor>();
@ -1018,14 +1040,16 @@ class NamenodeJspHelper {
final BlockManager blockManager; final BlockManager blockManager;
XMLBlockInfo(FSNamesystem fsn, Long blockId) { XMLBlockInfo(FSNamesystem fsn, Long blockId) {
this.blockManager = fsn.getBlockManager(); this.blockManager = fsn != null ? fsn.getBlockManager() : null;
if (blockId == null) { if (blockId == null) {
this.block = null; this.block = null;
this.inode = null; this.inode = null;
} else { } else {
this.block = new Block(blockId); this.block = new Block(blockId);
this.inode = ((INode)blockManager.getBlockCollection(block)).asFile(); this.inode = blockManager != null ?
((INode)blockManager.getBlockCollection(block)).asFile() :
null;
} }
} }
@ -1099,7 +1123,9 @@ class NamenodeJspHelper {
} }
doc.startTag("replicas"); doc.startTag("replicas");
for(final Iterator<DatanodeDescriptor> it = blockManager.datanodeIterator(block); for (final Iterator<DatanodeDescriptor> it = blockManager != null ?
blockManager.datanodeIterator(block) :
Collections.<DatanodeDescriptor>emptyList().iterator();
it.hasNext();) { it.hasNext();) {
doc.startTag("replica"); doc.startTag("replica");
@ -1136,7 +1162,7 @@ class NamenodeJspHelper {
XMLCorruptBlockInfo(FSNamesystem fsn, Configuration conf, XMLCorruptBlockInfo(FSNamesystem fsn, Configuration conf,
int numCorruptBlocks, Long startingBlockId) { int numCorruptBlocks, Long startingBlockId) {
this.blockManager = fsn.getBlockManager(); this.blockManager = fsn != null ? fsn.getBlockManager() : null;
this.conf = conf; this.conf = conf;
this.numCorruptBlocks = numCorruptBlocks; this.numCorruptBlocks = numCorruptBlocks;
this.startingBlockId = startingBlockId; this.startingBlockId = startingBlockId;
@ -1159,16 +1185,19 @@ class NamenodeJspHelper {
doc.endTag(); doc.endTag();
doc.startTag("num_missing_blocks"); doc.startTag("num_missing_blocks");
doc.pcdata(""+blockManager.getMissingBlocksCount()); doc.pcdata("" + (blockManager != null ?
blockManager.getMissingBlocksCount() : 0));
doc.endTag(); doc.endTag();
doc.startTag("num_corrupt_replica_blocks"); doc.startTag("num_corrupt_replica_blocks");
doc.pcdata(""+blockManager.getCorruptReplicaBlocksCount()); doc.pcdata("" + (blockManager != null ?
blockManager.getCorruptReplicaBlocksCount() : 0));
doc.endTag(); doc.endTag();
doc.startTag("corrupt_replica_block_ids"); doc.startTag("corrupt_replica_block_ids");
final long[] corruptBlockIds = blockManager.getCorruptReplicaBlockIds( final long[] corruptBlockIds = blockManager != null ?
numCorruptBlocks, startingBlockId); blockManager.getCorruptReplicaBlockIds(numCorruptBlocks,
startingBlockId) : null;
if (corruptBlockIds != null) { if (corruptBlockIds != null) {
for (Long blockId: corruptBlockIds) { for (Long blockId: corruptBlockIds) {
doc.startTag("block_id"); doc.startTag("block_id");

View File

@ -25,6 +25,7 @@
import="org.apache.hadoop.fs.Path" import="org.apache.hadoop.fs.Path"
import="org.apache.hadoop.ha.HAServiceProtocol.HAServiceState" import="org.apache.hadoop.ha.HAServiceProtocol.HAServiceState"
import="java.util.Collection" import="java.util.Collection"
import="java.util.Collections"
import="java.util.Arrays" %> import="java.util.Arrays" %>
<%!//for java.io.Serializable <%!//for java.io.Serializable
private static final long serialVersionUID = 1L;%> private static final long serialVersionUID = 1L;%>
@ -34,9 +35,10 @@
HAServiceState nnHAState = nn.getServiceState(); HAServiceState nnHAState = nn.getServiceState();
boolean isActive = (nnHAState == HAServiceState.ACTIVE); boolean isActive = (nnHAState == HAServiceState.ACTIVE);
String namenodeRole = nn.getRole().toString(); String namenodeRole = nn.getRole().toString();
String namenodeLabel = nn.getNameNodeAddressHostPortString(); String namenodeLabel = NamenodeJspHelper.getNameNodeLabel(nn);
Collection<FSNamesystem.CorruptFileBlockInfo> corruptFileBlocks = Collection<FSNamesystem.CorruptFileBlockInfo> corruptFileBlocks = fsn != null ?
fsn.listCorruptFileBlocks("/", null); fsn.listCorruptFileBlocks("/", null) :
Collections.<FSNamesystem.CorruptFileBlockInfo>emptyList();
int corruptFileCount = corruptFileBlocks.size(); int corruptFileCount = corruptFileBlocks.size();
%> %>
@ -48,7 +50,7 @@
<h1><%=namenodeRole%> '<%=namenodeLabel%>'</h1> <h1><%=namenodeRole%> '<%=namenodeLabel%>'</h1>
<%=NamenodeJspHelper.getVersionTable(fsn)%> <%=NamenodeJspHelper.getVersionTable(fsn)%>
<br> <br>
<% if (isActive) { %> <% if (isActive && fsn != null) { %>
<b><a href="/nn_browsedfscontent.jsp">Browse the filesystem</a></b> <b><a href="/nn_browsedfscontent.jsp">Browse the filesystem</a></b>
<br> <br>
<% } %> <% } %>

View File

@ -34,29 +34,20 @@
boolean isActive = (nnHAState == HAServiceState.ACTIVE); boolean isActive = (nnHAState == HAServiceState.ACTIVE);
String namenodeRole = nn.getRole().toString(); String namenodeRole = nn.getRole().toString();
String namenodeState = nnHAState.toString(); String namenodeState = nnHAState.toString();
String namenodeLabel = nn.getRpcServer() != null ? String namenodeLabel = NamenodeJspHelper.getNameNodeLabel(nn);
nn.getNameNodeAddressHostPortString() : null;
%> %>
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<link rel="stylesheet" type="text/css" href="/static/hadoop.css"> <link rel="stylesheet" type="text/css" href="/static/hadoop.css">
<% if (namenodeLabel != null) { %>
<title>Hadoop <%=namenodeRole%>&nbsp;<%=namenodeLabel%></title> <title>Hadoop <%=namenodeRole%>&nbsp;<%=namenodeLabel%></title>
<% } else { %>
<title>Hadoop <%=namenodeRole%></title>
<% } %>
</head> </head>
<body> <body>
<% if (namenodeLabel != null) { %>
<h1><%=namenodeRole%> '<%=namenodeLabel%>' (<%=namenodeState%>)</h1> <h1><%=namenodeRole%> '<%=namenodeLabel%>' (<%=namenodeState%>)</h1>
<% } else { %>
<h1><%=namenodeRole%> (<%=namenodeState%>)</h1>
<% } %>
<%= NamenodeJspHelper.getVersionTable(fsn) %> <%= NamenodeJspHelper.getVersionTable(fsn) %>
<br /> <br />
<% if (isActive) { %> <% if (isActive && fsn != null) { %>
<b><a href="/nn_browsedfscontent.jsp">Browse the filesystem</a></b><br> <b><a href="/nn_browsedfscontent.jsp">Browse the filesystem</a></b><br>
<% } %> <% } %>
<b><a href="/logs/"><%=namenodeRole%> Logs</a></b> <b><a href="/logs/"><%=namenodeRole%> Logs</a></b>

View File

@ -33,7 +33,7 @@ String namenodeRole = nn.getRole().toString();
FSNamesystem fsn = nn.getNamesystem(); FSNamesystem fsn = nn.getNamesystem();
HAServiceState nnHAState = nn.getServiceState(); HAServiceState nnHAState = nn.getServiceState();
boolean isActive = (nnHAState == HAServiceState.ACTIVE); boolean isActive = (nnHAState == HAServiceState.ACTIVE);
String namenodeLabel = nn.getNameNodeAddressHostPortString(); String namenodeLabel = NamenodeJspHelper.getNameNodeLabel(nn);
%> %>
<!DOCTYPE html> <!DOCTYPE html>
@ -46,7 +46,7 @@ String namenodeLabel = nn.getNameNodeAddressHostPortString();
<h1><%=namenodeRole%> '<%=namenodeLabel%>'</h1> <h1><%=namenodeRole%> '<%=namenodeLabel%>'</h1>
<%= NamenodeJspHelper.getVersionTable(fsn) %> <%= NamenodeJspHelper.getVersionTable(fsn) %>
<br /> <br />
<% if (isActive) { %> <% if (isActive && fsn != null) { %>
<b><a href="/nn_browsedfscontent.jsp">Browse the filesystem</a></b><br> <b><a href="/nn_browsedfscontent.jsp">Browse the filesystem</a></b><br>
<% } %> <% } %>
<b><a href="/logs/"><%=namenodeRole%> Logs</a></b><br> <b><a href="/logs/"><%=namenodeRole%> Logs</a></b><br>

View File

@ -25,12 +25,15 @@ import static org.apache.hadoop.hdfs.server.namenode.startupprogress.Phase.SAVIN
import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter; import javax.servlet.jsp.JspWriter;
import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.conf.Configuration;
@ -45,6 +48,7 @@ import org.junit.Assert;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.znerd.xmlenc.XMLOutputter;
public class TestNameNodeJspHelper { public class TestNameNodeJspHelper {
@ -117,6 +121,75 @@ public class TestNameNodeJspHelper {
Assert.assertEquals("", NamenodeJspHelper.getRollingUpgradeText(null)); Assert.assertEquals("", NamenodeJspHelper.getRollingUpgradeText(null));
} }
/**
* Tests for non-null, non-empty NameNode label.
*/
@Test
public void testGetNameNodeLabel() {
String nameNodeLabel = NamenodeJspHelper.getNameNodeLabel(
cluster.getNameNode());
Assert.assertNotNull(nameNodeLabel);
Assert.assertFalse(nameNodeLabel.isEmpty());
}
/**
* Tests for non-null, non-empty NameNode label when called before
* initialization of the NameNode RPC server.
*/
@Test
public void testGetNameNodeLabelNullRpcServer() {
NameNode nn = mock(NameNode.class);
when(nn.getRpcServer()).thenReturn(null);
String nameNodeLabel = NamenodeJspHelper.getNameNodeLabel(
cluster.getNameNode());
Assert.assertNotNull(nameNodeLabel);
Assert.assertFalse(nameNodeLabel.isEmpty());
}
/**
* Tests that passing a null FSNamesystem to generateSnapshotReport does not
* throw NullPointerException.
*/
@Test
public void testGenerateSnapshotReportNullNamesystem() throws Exception {
NamenodeJspHelper.generateSnapshotReport(mock(JspWriter.class), null);
}
/**
* Tests that redirectToRandomDataNode does not throw NullPointerException if
* it finds a null FSNamesystem.
*/
@Test(expected=IOException.class)
public void testRedirectToRandomDataNodeNullNamesystem() throws Exception {
NameNode nn = mock(NameNode.class);
when(nn.getNamesystem()).thenReturn(null);
ServletContext context = mock(ServletContext.class);
when(context.getAttribute("name.node")).thenReturn(nn);
NamenodeJspHelper.redirectToRandomDataNode(context,
mock(HttpServletRequest.class), mock(HttpServletResponse.class));
}
/**
* Tests that XMLBlockInfo does not throw NullPointerException if it finds a
* null FSNamesystem.
*/
@Test
public void testXMLBlockInfoNullNamesystem() throws IOException {
XMLOutputter doc = new XMLOutputter(mock(JspWriter.class), "UTF-8");
new NamenodeJspHelper.XMLBlockInfo(null, 1L).toXML(doc);
}
/**
* Tests that XMLCorruptBlockInfo does not throw NullPointerException if it
* finds a null FSNamesystem.
*/
@Test
public void testXMLCorruptBlockInfoNullNamesystem() throws IOException {
XMLOutputter doc = new XMLOutputter(mock(JspWriter.class), "UTF-8");
new NamenodeJspHelper.XMLCorruptBlockInfo(null, mock(Configuration.class),
10, 1L).toXML(doc);
}
/** /**
* Checks if the list contains any string that partially matches the regex. * Checks if the list contains any string that partially matches the regex.
* *