HDFS-12910. Secure Datanode Starter should log the port when it fails to bind. Contributed by Stephen O'Donnell and Nanda kumar.
This commit is contained in:
parent
95d4ec7fc0
commit
e1cb278cd0
|
@ -32,6 +32,7 @@ import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.nio.channels.ServerSocketChannel;
|
import java.nio.channels.ServerSocketChannel;
|
||||||
|
import java.net.BindException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class to start a datanode in a secure cluster, first obtaining
|
* Utility class to start a datanode in a secure cluster, first obtaining
|
||||||
|
@ -102,7 +103,13 @@ public class SecureDataNodeStarter implements Daemon {
|
||||||
|
|
||||||
ServerSocket ss = (socketWriteTimeout > 0) ?
|
ServerSocket ss = (socketWriteTimeout > 0) ?
|
||||||
ServerSocketChannel.open().socket() : new ServerSocket();
|
ServerSocketChannel.open().socket() : new ServerSocket();
|
||||||
|
try {
|
||||||
ss.bind(streamingAddr, backlogLength);
|
ss.bind(streamingAddr, backlogLength);
|
||||||
|
} catch (BindException e) {
|
||||||
|
BindException newBe = appendMessageToBindException(e,
|
||||||
|
streamingAddr.toString());
|
||||||
|
throw newBe;
|
||||||
|
}
|
||||||
|
|
||||||
// Check that we got the port we need
|
// Check that we got the port we need
|
||||||
if (ss.getLocalPort() != streamingAddr.getPort()) {
|
if (ss.getLocalPort() != streamingAddr.getPort()) {
|
||||||
|
@ -126,13 +133,20 @@ public class SecureDataNodeStarter implements Daemon {
|
||||||
if (policy.isHttpEnabled()) {
|
if (policy.isHttpEnabled()) {
|
||||||
httpChannel = ServerSocketChannel.open();
|
httpChannel = ServerSocketChannel.open();
|
||||||
InetSocketAddress infoSocAddr = DataNode.getInfoAddr(conf);
|
InetSocketAddress infoSocAddr = DataNode.getInfoAddr(conf);
|
||||||
|
try {
|
||||||
httpChannel.socket().bind(infoSocAddr);
|
httpChannel.socket().bind(infoSocAddr);
|
||||||
|
} catch (BindException e) {
|
||||||
|
BindException newBe = appendMessageToBindException(e,
|
||||||
|
infoSocAddr.toString());
|
||||||
|
throw newBe;
|
||||||
|
}
|
||||||
InetSocketAddress localAddr = (InetSocketAddress) httpChannel.socket()
|
InetSocketAddress localAddr = (InetSocketAddress) httpChannel.socket()
|
||||||
.getLocalSocketAddress();
|
.getLocalSocketAddress();
|
||||||
|
|
||||||
if (localAddr.getPort() != infoSocAddr.getPort()) {
|
if (localAddr.getPort() != infoSocAddr.getPort()) {
|
||||||
throw new RuntimeException("Unable to bind on specified info port in secure " +
|
throw new RuntimeException("Unable to bind on specified info port in " +
|
||||||
"context. Needed " + streamingAddr.getPort() + ", got " + ss.getLocalPort());
|
"secure context. Needed " + infoSocAddr.getPort() + ", got " +
|
||||||
|
ss.getLocalPort());
|
||||||
}
|
}
|
||||||
System.err.println("Successfully obtained privileged resources (streaming port = "
|
System.err.println("Successfully obtained privileged resources (streaming port = "
|
||||||
+ ss + " ) (http listener port = " + localAddr.getPort() +")");
|
+ ss + " ) (http listener port = " + localAddr.getPort() +")");
|
||||||
|
@ -149,4 +163,11 @@ public class SecureDataNodeStarter implements Daemon {
|
||||||
return new SecureResources(ss, httpChannel);
|
return new SecureResources(ss, httpChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static BindException appendMessageToBindException(BindException e,
|
||||||
|
String msg) {
|
||||||
|
BindException newBe = new BindException(e.getMessage() + " " + msg);
|
||||||
|
newBe.initCause(e.getCause());
|
||||||
|
newBe.setStackTrace(e.getStackTrace());
|
||||||
|
return newBe;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,9 +26,14 @@ import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
||||||
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
import static org.apache.hadoop.security.SecurityUtilTestHelper.isExternalKdcRunning;
|
import static org.apache.hadoop.security.SecurityUtilTestHelper.isExternalKdcRunning;
|
||||||
|
import org.apache.hadoop.net.NetUtils;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.Before;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.rules.ExpectedException;
|
||||||
|
import java.net.BindException;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.ServerSocket;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test starts a 1 NameNode 1 DataNode MiniDFSCluster with
|
* This test starts a 1 NameNode 1 DataNode MiniDFSCluster with
|
||||||
|
@ -48,16 +53,18 @@ import org.junit.Test;
|
||||||
* dfs.datanode.keytab.file
|
* dfs.datanode.keytab.file
|
||||||
*/
|
*/
|
||||||
public class TestStartSecureDataNode {
|
public class TestStartSecureDataNode {
|
||||||
|
@Rule
|
||||||
|
public ExpectedException thrown = ExpectedException.none();
|
||||||
final static private int NUM_OF_DATANODES = 1;
|
final static private int NUM_OF_DATANODES = 1;
|
||||||
|
|
||||||
@Before
|
private void testExternalKdcRunning() {
|
||||||
public void testExternalKdcRunning() {
|
|
||||||
// Tests are skipped if external KDC is not running.
|
// Tests are skipped if external KDC is not running.
|
||||||
Assume.assumeTrue(isExternalKdcRunning());
|
Assume.assumeTrue(isExternalKdcRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSecureNameNode() throws Exception {
|
public void testSecureNameNode() throws Exception {
|
||||||
|
testExternalKdcRunning();
|
||||||
MiniDFSCluster cluster = null;
|
MiniDFSCluster cluster = null;
|
||||||
try {
|
try {
|
||||||
String nnPrincipal =
|
String nnPrincipal =
|
||||||
|
@ -104,4 +111,55 @@ public class TestStartSecureDataNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test doesn't require KDC or other security settings as it expects
|
||||||
|
* {@link java.net.BindException}. Testing is done with unprivileged port
|
||||||
|
* for {@code dfs.datanode.address}.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testStreamingAddrBindException() throws Exception {
|
||||||
|
ServerSocket ss = new ServerSocket();
|
||||||
|
try {
|
||||||
|
ss.bind(new InetSocketAddress("localhost", 0));
|
||||||
|
thrown.expect(BindException.class);
|
||||||
|
thrown.expectMessage("localhost/127.0.0.1:" + ss.getLocalPort());
|
||||||
|
|
||||||
|
Configuration conf = new HdfsConfiguration();
|
||||||
|
conf.set(DFSConfigKeys.DFS_DATANODE_ADDRESS_KEY,
|
||||||
|
"localhost:" + ss.getLocalPort());
|
||||||
|
SecureDataNodeStarter.getSecureResources(conf);
|
||||||
|
} finally {
|
||||||
|
ss.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test doesn't require KDC or other security settings as it expects
|
||||||
|
* {@link java.net.BindException}. Testing is done with unprivileged port
|
||||||
|
* for {@code dfs.datanode.http.address}.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testWebServerAddrBindException() throws Exception {
|
||||||
|
ServerSocket ss = new ServerSocket();
|
||||||
|
try {
|
||||||
|
ss.bind(new InetSocketAddress("localhost", 0));
|
||||||
|
thrown.expect(BindException.class);
|
||||||
|
thrown.expectMessage("localhost/127.0.0.1:" + ss.getLocalPort());
|
||||||
|
|
||||||
|
Configuration conf = new HdfsConfiguration();
|
||||||
|
conf.set(DFSConfigKeys.DFS_DATANODE_ADDRESS_KEY,
|
||||||
|
"localhost:" + NetUtils.getFreeSocketPort());
|
||||||
|
conf.set(DFSConfigKeys.DFS_DATANODE_HTTP_ADDRESS_KEY,
|
||||||
|
"localhost:" + ss.getLocalPort());
|
||||||
|
|
||||||
|
SecureDataNodeStarter.getSecureResources(conf);
|
||||||
|
} finally {
|
||||||
|
ss.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue