HDFS-2545. Change WebHDFS to support multiple namenodes in federation.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1214027 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
a839f875e8
commit
433a6e78f6
|
@ -175,6 +175,9 @@ Release 0.23.1 - UNRELEASED
|
||||||
HDFS-2594. Support getDelegationTokens and createSymlink in WebHDFS.
|
HDFS-2594. Support getDelegationTokens and createSymlink in WebHDFS.
|
||||||
(szetszwo)
|
(szetszwo)
|
||||||
|
|
||||||
|
HDFS-2545. Change WebHDFS to support multiple namenodes in federation.
|
||||||
|
(szetszwo)
|
||||||
|
|
||||||
IMPROVEMENTS
|
IMPROVEMENTS
|
||||||
HDFS-2560. Refactor BPOfferService to be a static inner class (todd)
|
HDFS-2560. Refactor BPOfferService to be a static inner class (todd)
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ import org.apache.hadoop.hdfs.web.resources.DelegationParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.GetOpParam;
|
import org.apache.hadoop.hdfs.web.resources.GetOpParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.HttpOpParam;
|
import org.apache.hadoop.hdfs.web.resources.HttpOpParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.LengthParam;
|
import org.apache.hadoop.hdfs.web.resources.LengthParam;
|
||||||
|
import org.apache.hadoop.hdfs.web.resources.NamenodeRpcAddressParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.OffsetParam;
|
import org.apache.hadoop.hdfs.web.resources.OffsetParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.OverwriteParam;
|
import org.apache.hadoop.hdfs.web.resources.OverwriteParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.Param;
|
import org.apache.hadoop.hdfs.web.resources.Param;
|
||||||
|
@ -89,7 +90,8 @@ public class DatanodeWebHdfsMethods {
|
||||||
private @Context ServletContext context;
|
private @Context ServletContext context;
|
||||||
private @Context HttpServletResponse response;
|
private @Context HttpServletResponse response;
|
||||||
|
|
||||||
private void init(final UserGroupInformation ugi, final DelegationParam delegation,
|
private void init(final UserGroupInformation ugi,
|
||||||
|
final DelegationParam delegation, final InetSocketAddress nnRpcAddr,
|
||||||
final UriFsPathParam path, final HttpOpParam<?> op,
|
final UriFsPathParam path, final HttpOpParam<?> op,
|
||||||
final Param<?, ?>... parameters) throws IOException {
|
final Param<?, ?>... parameters) throws IOException {
|
||||||
if (LOG.isTraceEnabled()) {
|
if (LOG.isTraceEnabled()) {
|
||||||
|
@ -102,9 +104,8 @@ public class DatanodeWebHdfsMethods {
|
||||||
|
|
||||||
if (UserGroupInformation.isSecurityEnabled()) {
|
if (UserGroupInformation.isSecurityEnabled()) {
|
||||||
//add a token for RPC.
|
//add a token for RPC.
|
||||||
final DataNode datanode = (DataNode)context.getAttribute("datanode");
|
final Token<DelegationTokenIdentifier> token =
|
||||||
final InetSocketAddress nnRpcAddr = NameNode.getAddress(datanode.getConf());
|
new Token<DelegationTokenIdentifier>();
|
||||||
final Token<DelegationTokenIdentifier> token = new Token<DelegationTokenIdentifier>();
|
|
||||||
token.decodeFromUrlString(delegation.getValue());
|
token.decodeFromUrlString(delegation.getValue());
|
||||||
SecurityUtil.setTokenService(token, nnRpcAddr);
|
SecurityUtil.setTokenService(token, nnRpcAddr);
|
||||||
token.setKind(DelegationTokenIdentifier.HDFS_DELEGATION_KIND);
|
token.setKind(DelegationTokenIdentifier.HDFS_DELEGATION_KIND);
|
||||||
|
@ -122,6 +123,9 @@ public class DatanodeWebHdfsMethods {
|
||||||
@Context final UserGroupInformation ugi,
|
@Context final UserGroupInformation ugi,
|
||||||
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
||||||
final DelegationParam delegation,
|
final DelegationParam delegation,
|
||||||
|
@QueryParam(NamenodeRpcAddressParam.NAME)
|
||||||
|
@DefaultValue(NamenodeRpcAddressParam.DEFAULT)
|
||||||
|
final NamenodeRpcAddressParam namenodeRpcAddress,
|
||||||
@QueryParam(PutOpParam.NAME) @DefaultValue(PutOpParam.DEFAULT)
|
@QueryParam(PutOpParam.NAME) @DefaultValue(PutOpParam.DEFAULT)
|
||||||
final PutOpParam op,
|
final PutOpParam op,
|
||||||
@QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT)
|
@QueryParam(PermissionParam.NAME) @DefaultValue(PermissionParam.DEFAULT)
|
||||||
|
@ -135,8 +139,8 @@ public class DatanodeWebHdfsMethods {
|
||||||
@QueryParam(BlockSizeParam.NAME) @DefaultValue(BlockSizeParam.DEFAULT)
|
@QueryParam(BlockSizeParam.NAME) @DefaultValue(BlockSizeParam.DEFAULT)
|
||||||
final BlockSizeParam blockSize
|
final BlockSizeParam blockSize
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
return put(in, ugi, delegation, ROOT, op, permission, overwrite, bufferSize,
|
return put(in, ugi, delegation, namenodeRpcAddress, ROOT, op, permission,
|
||||||
replication, blockSize);
|
overwrite, bufferSize, replication, blockSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle HTTP PUT request. */
|
/** Handle HTTP PUT request. */
|
||||||
|
@ -149,6 +153,9 @@ public class DatanodeWebHdfsMethods {
|
||||||
@Context final UserGroupInformation ugi,
|
@Context final UserGroupInformation ugi,
|
||||||
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
||||||
final DelegationParam delegation,
|
final DelegationParam delegation,
|
||||||
|
@QueryParam(NamenodeRpcAddressParam.NAME)
|
||||||
|
@DefaultValue(NamenodeRpcAddressParam.DEFAULT)
|
||||||
|
final NamenodeRpcAddressParam namenodeRpcAddress,
|
||||||
@PathParam(UriFsPathParam.NAME) final UriFsPathParam path,
|
@PathParam(UriFsPathParam.NAME) final UriFsPathParam path,
|
||||||
@QueryParam(PutOpParam.NAME) @DefaultValue(PutOpParam.DEFAULT)
|
@QueryParam(PutOpParam.NAME) @DefaultValue(PutOpParam.DEFAULT)
|
||||||
final PutOpParam op,
|
final PutOpParam op,
|
||||||
|
@ -164,8 +171,9 @@ public class DatanodeWebHdfsMethods {
|
||||||
final BlockSizeParam blockSize
|
final BlockSizeParam blockSize
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
|
|
||||||
init(ugi, delegation, path, op, permission, overwrite, bufferSize,
|
final InetSocketAddress nnRpcAddr = namenodeRpcAddress.getValue();
|
||||||
replication, blockSize);
|
init(ugi, delegation, nnRpcAddr, path, op, permission,
|
||||||
|
overwrite, bufferSize, replication, blockSize);
|
||||||
|
|
||||||
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -178,7 +186,6 @@ public class DatanodeWebHdfsMethods {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
{
|
{
|
||||||
final Configuration conf = new Configuration(datanode.getConf());
|
final Configuration conf = new Configuration(datanode.getConf());
|
||||||
final InetSocketAddress nnRpcAddr = NameNode.getAddress(conf);
|
|
||||||
conf.set(FsPermission.UMASK_LABEL, "000");
|
conf.set(FsPermission.UMASK_LABEL, "000");
|
||||||
|
|
||||||
final int b = bufferSize.getValue(conf);
|
final int b = bufferSize.getValue(conf);
|
||||||
|
@ -221,12 +228,15 @@ public class DatanodeWebHdfsMethods {
|
||||||
@Context final UserGroupInformation ugi,
|
@Context final UserGroupInformation ugi,
|
||||||
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
||||||
final DelegationParam delegation,
|
final DelegationParam delegation,
|
||||||
|
@QueryParam(NamenodeRpcAddressParam.NAME)
|
||||||
|
@DefaultValue(NamenodeRpcAddressParam.DEFAULT)
|
||||||
|
final NamenodeRpcAddressParam namenodeRpcAddress,
|
||||||
@QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT)
|
@QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT)
|
||||||
final PostOpParam op,
|
final PostOpParam op,
|
||||||
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
||||||
final BufferSizeParam bufferSize
|
final BufferSizeParam bufferSize
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
return post(in, ugi, delegation, ROOT, op, bufferSize);
|
return post(in, ugi, delegation, namenodeRpcAddress, ROOT, op, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle HTTP POST request. */
|
/** Handle HTTP POST request. */
|
||||||
|
@ -239,6 +249,9 @@ public class DatanodeWebHdfsMethods {
|
||||||
@Context final UserGroupInformation ugi,
|
@Context final UserGroupInformation ugi,
|
||||||
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
||||||
final DelegationParam delegation,
|
final DelegationParam delegation,
|
||||||
|
@QueryParam(NamenodeRpcAddressParam.NAME)
|
||||||
|
@DefaultValue(NamenodeRpcAddressParam.DEFAULT)
|
||||||
|
final NamenodeRpcAddressParam namenodeRpcAddress,
|
||||||
@PathParam(UriFsPathParam.NAME) final UriFsPathParam path,
|
@PathParam(UriFsPathParam.NAME) final UriFsPathParam path,
|
||||||
@QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT)
|
@QueryParam(PostOpParam.NAME) @DefaultValue(PostOpParam.DEFAULT)
|
||||||
final PostOpParam op,
|
final PostOpParam op,
|
||||||
|
@ -246,7 +259,8 @@ public class DatanodeWebHdfsMethods {
|
||||||
final BufferSizeParam bufferSize
|
final BufferSizeParam bufferSize
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
|
|
||||||
init(ugi, delegation, path, op, bufferSize);
|
final InetSocketAddress nnRpcAddr = namenodeRpcAddress.getValue();
|
||||||
|
init(ugi, delegation, nnRpcAddr, path, op, bufferSize);
|
||||||
|
|
||||||
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -259,7 +273,6 @@ public class DatanodeWebHdfsMethods {
|
||||||
case APPEND:
|
case APPEND:
|
||||||
{
|
{
|
||||||
final Configuration conf = new Configuration(datanode.getConf());
|
final Configuration conf = new Configuration(datanode.getConf());
|
||||||
final InetSocketAddress nnRpcAddr = NameNode.getAddress(conf);
|
|
||||||
final int b = bufferSize.getValue(conf);
|
final int b = bufferSize.getValue(conf);
|
||||||
DFSClient dfsclient = new DFSClient(nnRpcAddr, conf);
|
DFSClient dfsclient = new DFSClient(nnRpcAddr, conf);
|
||||||
FSDataOutputStream out = null;
|
FSDataOutputStream out = null;
|
||||||
|
@ -291,6 +304,9 @@ public class DatanodeWebHdfsMethods {
|
||||||
@Context final UserGroupInformation ugi,
|
@Context final UserGroupInformation ugi,
|
||||||
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
||||||
final DelegationParam delegation,
|
final DelegationParam delegation,
|
||||||
|
@QueryParam(NamenodeRpcAddressParam.NAME)
|
||||||
|
@DefaultValue(NamenodeRpcAddressParam.DEFAULT)
|
||||||
|
final NamenodeRpcAddressParam namenodeRpcAddress,
|
||||||
@QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT)
|
@QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT)
|
||||||
final GetOpParam op,
|
final GetOpParam op,
|
||||||
@QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT)
|
@QueryParam(OffsetParam.NAME) @DefaultValue(OffsetParam.DEFAULT)
|
||||||
|
@ -300,7 +316,8 @@ public class DatanodeWebHdfsMethods {
|
||||||
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
@QueryParam(BufferSizeParam.NAME) @DefaultValue(BufferSizeParam.DEFAULT)
|
||||||
final BufferSizeParam bufferSize
|
final BufferSizeParam bufferSize
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
return get(ugi, delegation, ROOT, op, offset, length, bufferSize);
|
return get(ugi, delegation, namenodeRpcAddress, ROOT, op, offset, length,
|
||||||
|
bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Handle HTTP GET request. */
|
/** Handle HTTP GET request. */
|
||||||
|
@ -311,6 +328,9 @@ public class DatanodeWebHdfsMethods {
|
||||||
@Context final UserGroupInformation ugi,
|
@Context final UserGroupInformation ugi,
|
||||||
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
@QueryParam(DelegationParam.NAME) @DefaultValue(DelegationParam.DEFAULT)
|
||||||
final DelegationParam delegation,
|
final DelegationParam delegation,
|
||||||
|
@QueryParam(NamenodeRpcAddressParam.NAME)
|
||||||
|
@DefaultValue(NamenodeRpcAddressParam.DEFAULT)
|
||||||
|
final NamenodeRpcAddressParam namenodeRpcAddress,
|
||||||
@PathParam(UriFsPathParam.NAME) final UriFsPathParam path,
|
@PathParam(UriFsPathParam.NAME) final UriFsPathParam path,
|
||||||
@QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT)
|
@QueryParam(GetOpParam.NAME) @DefaultValue(GetOpParam.DEFAULT)
|
||||||
final GetOpParam op,
|
final GetOpParam op,
|
||||||
|
@ -322,7 +342,8 @@ public class DatanodeWebHdfsMethods {
|
||||||
final BufferSizeParam bufferSize
|
final BufferSizeParam bufferSize
|
||||||
) throws IOException, InterruptedException {
|
) throws IOException, InterruptedException {
|
||||||
|
|
||||||
init(ugi, delegation, path, op, offset, length, bufferSize);
|
final InetSocketAddress nnRpcAddr = namenodeRpcAddress.getValue();
|
||||||
|
init(ugi, delegation, nnRpcAddr, path, op, offset, length, bufferSize);
|
||||||
|
|
||||||
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
return ugi.doAs(new PrivilegedExceptionAction<Response>() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -331,7 +352,6 @@ public class DatanodeWebHdfsMethods {
|
||||||
final String fullpath = path.getAbsolutePath();
|
final String fullpath = path.getAbsolutePath();
|
||||||
final DataNode datanode = (DataNode)context.getAttribute("datanode");
|
final DataNode datanode = (DataNode)context.getAttribute("datanode");
|
||||||
final Configuration conf = new Configuration(datanode.getConf());
|
final Configuration conf = new Configuration(datanode.getConf());
|
||||||
final InetSocketAddress nnRpcAddr = NameNode.getAddress(conf);
|
|
||||||
|
|
||||||
switch(op.getValue()) {
|
switch(op.getValue()) {
|
||||||
case OPEN:
|
case OPEN:
|
||||||
|
|
|
@ -76,6 +76,7 @@ import org.apache.hadoop.hdfs.web.resources.GroupParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.HttpOpParam;
|
import org.apache.hadoop.hdfs.web.resources.HttpOpParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.LengthParam;
|
import org.apache.hadoop.hdfs.web.resources.LengthParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.ModificationTimeParam;
|
import org.apache.hadoop.hdfs.web.resources.ModificationTimeParam;
|
||||||
|
import org.apache.hadoop.hdfs.web.resources.NamenodeRpcAddressParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.OffsetParam;
|
import org.apache.hadoop.hdfs.web.resources.OffsetParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.OverwriteParam;
|
import org.apache.hadoop.hdfs.web.resources.OverwriteParam;
|
||||||
import org.apache.hadoop.hdfs.web.resources.OwnerParam;
|
import org.apache.hadoop.hdfs.web.resources.OwnerParam;
|
||||||
|
@ -198,6 +199,7 @@ public class NamenodeWebHdfsMethods {
|
||||||
delegationQuery = "&" + new DelegationParam(t.encodeToUrlString());
|
delegationQuery = "&" + new DelegationParam(t.encodeToUrlString());
|
||||||
}
|
}
|
||||||
final String query = op.toQueryString() + delegationQuery
|
final String query = op.toQueryString() + delegationQuery
|
||||||
|
+ "&" + new NamenodeRpcAddressParam(namenode)
|
||||||
+ Param.toSortedString("&", parameters);
|
+ Param.toSortedString("&", parameters);
|
||||||
final String uripath = WebHdfsFileSystem.PATH_PREFIX + path;
|
final String uripath = WebHdfsFileSystem.PATH_PREFIX + path;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.web.resources;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
|
||||||
|
/** InetSocketAddressParam parameter. */
|
||||||
|
abstract class InetSocketAddressParam
|
||||||
|
extends Param<InetSocketAddress, InetSocketAddressParam.Domain> {
|
||||||
|
InetSocketAddressParam(final Domain domain, final InetSocketAddress value) {
|
||||||
|
super(domain, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getName() + "=" + Domain.toString(getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The domain of the parameter. */
|
||||||
|
static final class Domain extends Param.Domain<InetSocketAddress> {
|
||||||
|
Domain(final String paramName) {
|
||||||
|
super(paramName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDomain() {
|
||||||
|
return "<HOST:PORT>";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
InetSocketAddress parse(final String str) {
|
||||||
|
final int i = str.indexOf(':');
|
||||||
|
if (i < 0) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse \"" + str
|
||||||
|
+ "\" as " + getDomain() + ": the ':' character not found.");
|
||||||
|
} else if (i == 0) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse \"" + str
|
||||||
|
+ "\" as " + getDomain() + ": HOST is empty.");
|
||||||
|
} else if (i == str.length() - 1) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse \"" + str
|
||||||
|
+ "\" as " + getDomain() + ": PORT is empty.");
|
||||||
|
}
|
||||||
|
|
||||||
|
final String host = str.substring(0, i);
|
||||||
|
final int port;
|
||||||
|
try {
|
||||||
|
port = Integer.parseInt(str.substring(i + 1));
|
||||||
|
} catch(NumberFormatException e) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse \"" + str
|
||||||
|
+ "\" as " + getDomain() + ": the ':' position is " + i
|
||||||
|
+ " but failed to parse PORT.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return new InetSocketAddress(host, port);
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new IllegalArgumentException("Failed to parse \"" + str
|
||||||
|
+ "\": cannot create InetSocketAddress(host=" + host
|
||||||
|
+ ", port=" + port + ")", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Convert an InetSocketAddress to a HOST:PORT String. */
|
||||||
|
static String toString(final InetSocketAddress addr) {
|
||||||
|
return addr.getHostName() + ":" + addr.getPort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.web.resources;
|
||||||
|
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.NameNode;
|
||||||
|
|
||||||
|
/** Namenode RPC address parameter. */
|
||||||
|
public class NamenodeRpcAddressParam extends InetSocketAddressParam {
|
||||||
|
/** Parameter name. */
|
||||||
|
public static final String NAME = "namenoderpcaddress";
|
||||||
|
/** Default parameter value. */
|
||||||
|
public static final String DEFAULT = "";
|
||||||
|
|
||||||
|
private static final Domain DOMAIN = new Domain(NAME);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param str a string representation of the parameter value.
|
||||||
|
*/
|
||||||
|
public NamenodeRpcAddressParam(final String str) {
|
||||||
|
super(DOMAIN, str == null || str.equals(DEFAULT)? null: DOMAIN.parse(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct an object using the RPC address of the given namenode.
|
||||||
|
*/
|
||||||
|
public NamenodeRpcAddressParam(final NameNode namenode) {
|
||||||
|
super(DOMAIN, namenode.getNameNodeAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return NAME;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
/**
|
||||||
|
* 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.hdfs.web;
|
||||||
|
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.apache.commons.logging.impl.Log4JLogger;
|
||||||
|
import org.apache.hadoop.conf.Configuration;
|
||||||
|
import org.apache.hadoop.fs.FSDataInputStream;
|
||||||
|
import org.apache.hadoop.fs.FSDataOutputStream;
|
||||||
|
import org.apache.hadoop.fs.FileSystem;
|
||||||
|
import org.apache.hadoop.fs.Path;
|
||||||
|
import org.apache.hadoop.hdfs.DFSConfigKeys;
|
||||||
|
import org.apache.hadoop.hdfs.HdfsConfiguration;
|
||||||
|
import org.apache.hadoop.hdfs.MiniDFSCluster;
|
||||||
|
import org.apache.hadoop.hdfs.server.datanode.DataNode;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.FSNamesystem;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.LeaseManager;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.NameNode;
|
||||||
|
import org.apache.hadoop.hdfs.server.namenode.web.resources.NamenodeWebHdfsMethods;
|
||||||
|
import org.apache.log4j.Level;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Assert;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test WebHDFS with multiple NameNodes
|
||||||
|
*/
|
||||||
|
public class TestWebHdfsWithMultipleNameNodes {
|
||||||
|
static final Log LOG = WebHdfsTestUtil.LOG;
|
||||||
|
|
||||||
|
static private void setLogLevel() {
|
||||||
|
((Log4JLogger)LOG).getLogger().setLevel(Level.ALL);
|
||||||
|
((Log4JLogger)NamenodeWebHdfsMethods.LOG).getLogger().setLevel(Level.ALL);
|
||||||
|
|
||||||
|
((Log4JLogger)NameNode.stateChangeLog).getLogger().setLevel(Level.OFF);
|
||||||
|
((Log4JLogger)LeaseManager.LOG).getLogger().setLevel(Level.OFF);
|
||||||
|
((Log4JLogger)LogFactory.getLog(FSNamesystem.class)).getLogger().setLevel(Level.OFF);
|
||||||
|
((Log4JLogger)DataNode.LOG).getLogger().setLevel(Level.OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Configuration conf = new HdfsConfiguration();
|
||||||
|
private static MiniDFSCluster cluster;
|
||||||
|
private static WebHdfsFileSystem[] webhdfs;
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
public static void setupTest() {
|
||||||
|
setLogLevel();
|
||||||
|
try {
|
||||||
|
setupCluster(4, 3);
|
||||||
|
} catch(Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void setupCluster(final int nNameNodes, final int nDataNodes)
|
||||||
|
throws Exception {
|
||||||
|
LOG.info("nNameNodes=" + nNameNodes + ", nDataNodes=" + nDataNodes);
|
||||||
|
|
||||||
|
conf.setBoolean(DFSConfigKeys.DFS_WEBHDFS_ENABLED_KEY, true);
|
||||||
|
|
||||||
|
cluster = new MiniDFSCluster.Builder(conf)
|
||||||
|
.numNameNodes(nNameNodes)
|
||||||
|
.numDataNodes(nDataNodes)
|
||||||
|
.build();
|
||||||
|
cluster.waitActive();
|
||||||
|
|
||||||
|
webhdfs = new WebHdfsFileSystem[nNameNodes];
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
final InetSocketAddress addr = cluster.getNameNode(i).getHttpAddress();
|
||||||
|
final String uri = WebHdfsFileSystem.SCHEME + "://"
|
||||||
|
+ addr.getHostName() + ":" + addr.getPort() + "/";
|
||||||
|
webhdfs[i] = (WebHdfsFileSystem)FileSystem.get(new URI(uri), conf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void shutdownCluster() {
|
||||||
|
if (cluster != null) {
|
||||||
|
cluster.shutdown();
|
||||||
|
cluster = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String createString(String prefix, int i) {
|
||||||
|
//The suffix is to make sure the strings have different lengths.
|
||||||
|
final String suffix = "*********************".substring(0, i+1);
|
||||||
|
return prefix + i + suffix + "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String[] createStrings(String prefix, String name) {
|
||||||
|
final String[] strings = new String[webhdfs.length];
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
strings[i] = createString(prefix, i);
|
||||||
|
LOG.info(name + "[" + i + "] = " + strings[i]);
|
||||||
|
}
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRedirect() throws Exception {
|
||||||
|
final String dir = "/testRedirect/";
|
||||||
|
final String filename = "file";
|
||||||
|
final Path p = new Path(dir, filename);
|
||||||
|
|
||||||
|
final String[] writeStrings = createStrings("write to webhdfs ", "write");
|
||||||
|
final String[] appendStrings = createStrings("append to webhdfs ", "append");
|
||||||
|
|
||||||
|
//test create: create a file for each namenode
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
final FSDataOutputStream out = webhdfs[i].create(p);
|
||||||
|
out.write(writeStrings[i].getBytes());
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
//check file length
|
||||||
|
final long expected = writeStrings[i].length();
|
||||||
|
Assert.assertEquals(expected, webhdfs[i].getFileStatus(p).getLen());
|
||||||
|
}
|
||||||
|
|
||||||
|
//test read: check file content for each namenode
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
final FSDataInputStream in = webhdfs[i].open(p);
|
||||||
|
for(int c, j = 0; (c = in.read()) != -1; j++) {
|
||||||
|
Assert.assertEquals(writeStrings[i].charAt(j), c);
|
||||||
|
}
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//test append: append to the file for each namenode
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
final FSDataOutputStream out = webhdfs[i].append(p);
|
||||||
|
out.write(appendStrings[i].getBytes());
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
//check file length
|
||||||
|
final long expected = writeStrings[i].length() + appendStrings[i].length();
|
||||||
|
Assert.assertEquals(expected, webhdfs[i].getFileStatus(p).getLen());
|
||||||
|
}
|
||||||
|
|
||||||
|
//test read: check file content for each namenode
|
||||||
|
for(int i = 0; i < webhdfs.length; i++) {
|
||||||
|
final StringBuilder b = new StringBuilder();
|
||||||
|
final FSDataInputStream in = webhdfs[i].open(p);
|
||||||
|
for(int c; (c = in.read()) != -1; ) {
|
||||||
|
b.append((char)c);
|
||||||
|
}
|
||||||
|
final int wlen = writeStrings[i].length();
|
||||||
|
Assert.assertEquals(writeStrings[i], b.substring(0, wlen));
|
||||||
|
Assert.assertEquals(appendStrings[i], b.substring(wlen));
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue