blob: a5997b46a9154c984842225f476fc256a8e65297 [file] [log] [blame]
/**
* 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.nfs.nfs3;
import org.apache.hadoop.crypto.key.JavaKeyStoreProvider;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileSystemTestHelper;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.fs.FsConstants;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.viewfs.ConfigUtil;
import org.apache.hadoop.hdfs.DFSTestUtil;
import org.apache.hadoop.hdfs.DistributedFileSystem;
import org.apache.hadoop.hdfs.MiniDFSCluster;
import org.apache.hadoop.hdfs.MiniDFSNNTopology;
import org.apache.hadoop.hdfs.client.HdfsAdmin;
import org.apache.hadoop.hdfs.nfs.conf.NfsConfigKeys;
import org.apache.hadoop.hdfs.nfs.conf.NfsConfiguration;
import org.apache.hadoop.hdfs.nfs.mount.RpcProgramMountd;
import org.apache.hadoop.hdfs.protocol.HdfsFileStatus;
import org.apache.hadoop.hdfs.server.namenode.NameNode;
import org.apache.hadoop.nfs.nfs3.FileHandle;
import org.apache.hadoop.nfs.nfs3.Nfs3Constant;
import org.apache.hadoop.nfs.nfs3.Nfs3Status;
import org.apache.hadoop.nfs.nfs3.request.GETATTR3Request;
import org.apache.hadoop.nfs.nfs3.request.RENAME3Request;
import org.apache.hadoop.nfs.nfs3.response.GETATTR3Response;
import org.apache.hadoop.nfs.nfs3.request.WRITE3Request;
import org.apache.hadoop.nfs.nfs3.response.RENAME3Response;
import org.apache.hadoop.nfs.nfs3.response.WRITE3Response;
import org.apache.hadoop.oncrpc.XDR;
import org.apache.hadoop.oncrpc.security.SecurityHandler;
import org.apache.hadoop.security.authorize.DefaultImpersonationProvider;
import org.apache.hadoop.security.authorize.ProxyUsers;
import org.junit.BeforeClass;
import org.junit.AfterClass;
import org.junit.Test;
import org.junit.Assert;
import org.mockito.Mockito;
import java.io.File;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import static org.junit.Assert.assertEquals;
/**
* Tests for {@link RpcProgramNfs3} with
* {@link org.apache.hadoop.fs.viewfs.ViewFileSystem}.
*/
public class TestViewfsWithNfs3 {
private static DistributedFileSystem hdfs1;
private static DistributedFileSystem hdfs2;
private static MiniDFSCluster cluster = null;
private static NfsConfiguration config = new NfsConfiguration();
private static HdfsAdmin dfsAdmin1;
private static HdfsAdmin dfsAdmin2;
private static FileSystem viewFs;
private static NameNode nn1;
private static NameNode nn2;
private static Nfs3 nfs;
private static RpcProgramNfs3 nfsd;
private static RpcProgramMountd mountd;
private static SecurityHandler securityHandler;
private static FileSystemTestHelper fsHelper;
private static File testRootDir;
@BeforeClass
public static void setup() throws Exception {
String currentUser = System.getProperty("user.name");
config.set("fs.permissions.umask-mode", "u=rwx,g=,o=");
config.set(DefaultImpersonationProvider.getTestProvider()
.getProxySuperuserGroupConfKey(currentUser), "*");
config.set(DefaultImpersonationProvider.getTestProvider()
.getProxySuperuserIpConfKey(currentUser), "*");
fsHelper = new FileSystemTestHelper();
// Set up java key store
String testRoot = fsHelper.getTestRootDir();
testRootDir = new File(testRoot).getAbsoluteFile();
final Path jksPath = new Path(testRootDir.toString(), "test.jks");
config.set(CommonConfigurationKeysPublic.HADOOP_SECURITY_KEY_PROVIDER_PATH,
JavaKeyStoreProvider.SCHEME_NAME + "://file" + jksPath.toUri());
ProxyUsers.refreshSuperUserGroupsConfiguration(config);
cluster =
new MiniDFSCluster.Builder(config).nnTopology(
MiniDFSNNTopology.simpleFederatedTopology(2))
.numDataNodes(2)
.build();
cluster.waitActive();
hdfs1 = cluster.getFileSystem(0);
hdfs2 = cluster.getFileSystem(1);
nn1 = cluster.getNameNode(0);
nn2 = cluster.getNameNode(1);
nn2.getServiceRpcAddress();
dfsAdmin1 = new HdfsAdmin(cluster.getURI(0), config);
dfsAdmin2 = new HdfsAdmin(cluster.getURI(1), config);
// Use ephemeral ports in case tests are running in parallel
config.setInt("nfs3.mountd.port", 0);
config.setInt("nfs3.server.port", 0);
config.set(CommonConfigurationKeysPublic.FS_DEFAULT_NAME_KEY,
FsConstants.VIEWFS_URI.toString());
// Start NFS with allowed.hosts set to "* rw"
config.set("dfs.nfs.exports.allowed.hosts", "* rw");
Path base1 = new Path("/user1");
Path base2 = new Path("/user2");
hdfs1.delete(base1, true);
hdfs2.delete(base2, true);
hdfs1.mkdirs(base1);
hdfs2.mkdirs(base2);
ConfigUtil.addLink(config, "/hdfs1", hdfs1.makeQualified(base1).toUri());
ConfigUtil.addLink(config, "/hdfs2", hdfs2.makeQualified(base2).toUri());
viewFs = FileSystem.get(config);
config.setStrings(NfsConfigKeys.DFS_NFS_EXPORT_POINT_KEY,
"/hdfs1", "/hdfs2");
nfs = new Nfs3(config);
nfs.startServiceInternal(false);
nfsd = (RpcProgramNfs3) nfs.getRpcProgram();
mountd = (RpcProgramMountd) nfs.getMountd().getRpcProgram();
// Mock SecurityHandler which returns system user.name
securityHandler = Mockito.mock(SecurityHandler.class);
Mockito.when(securityHandler.getUser()).thenReturn(currentUser);
viewFs.delete(new Path("/hdfs2/dir2"), true);
viewFs.mkdirs(new Path("/hdfs2/dir2"));
DFSTestUtil.createFile(viewFs, new Path("/hdfs1/file1"), 0, (short) 1, 0);
DFSTestUtil.createFile(viewFs, new Path("/hdfs1/file2"), 0, (short) 1, 0);
DFSTestUtil.createFile(viewFs, new Path("/hdfs1/write1"), 0, (short) 1, 0);
DFSTestUtil.createFile(viewFs, new Path("/hdfs2/write2"), 0, (short) 1, 0);
DFSTestUtil.createFile(viewFs, new Path("/hdfs1/renameMultiNN"),
0, (short) 1, 0);
DFSTestUtil.createFile(viewFs, new Path("/hdfs1/renameSingleNN"),
0, (short) 1, 0);
}
@AfterClass
public static void shutdown() throws Exception {
if (cluster != null) {
cluster.shutdown();
}
}
@Test
public void testNumExports() throws Exception {
Assert.assertEquals(mountd.getExports().size(),
viewFs.getChildFileSystems().length);
}
@Test
public void testPaths() throws Exception {
Assert.assertEquals(hdfs1.resolvePath(new Path("/user1/file1")),
viewFs.resolvePath(new Path("/hdfs1/file1")));
Assert.assertEquals(hdfs1.resolvePath(new Path("/user1/file2")),
viewFs.resolvePath(new Path("/hdfs1/file2")));
Assert.assertEquals(hdfs2.resolvePath(new Path("/user2/dir2")),
viewFs.resolvePath(new Path("/hdfs2/dir2")));
}
@Test
public void testFileStatus() throws Exception {
HdfsFileStatus status = nn1.getRpcServer().getFileInfo("/user1/file1");
FileStatus st = viewFs.getFileStatus(new Path("/hdfs1/file1"));
Assert.assertEquals(st.isDirectory(), status.isDirectory());
HdfsFileStatus status2 = nn2.getRpcServer().getFileInfo("/user2/dir2");
FileStatus st2 = viewFs.getFileStatus(new Path("/hdfs2/dir2"));
Assert.assertEquals(st2.isDirectory(), status2.isDirectory());
}
// Test for getattr
private void testNfsGetAttrResponse(long fileId, int namenodeId,
int expectedStatus) {
FileHandle handle = new FileHandle(fileId, namenodeId);
XDR xdrReq = new XDR();
GETATTR3Request req = new GETATTR3Request(handle);
req.serialize(xdrReq);
GETATTR3Response response = nfsd.getattr(xdrReq.asReadOnlyWrap(),
securityHandler, new InetSocketAddress("localhost", 1234));
Assert.assertEquals("Incorrect return code",
expectedStatus, response.getStatus());
}
@Test (timeout = 60000)
public void testNfsAccessNN1() throws Exception {
HdfsFileStatus status = nn1.getRpcServer().getFileInfo("/user1/file1");
int namenodeId = Nfs3Utils.getNamenodeId(config, hdfs1.getUri());
testNfsGetAttrResponse(status.getFileId(), namenodeId, Nfs3Status.NFS3_OK);
}
@Test (timeout = 60000)
public void testNfsAccessNN2() throws Exception {
HdfsFileStatus status = nn2.getRpcServer().getFileInfo("/user2/dir2");
int namenodeId = Nfs3Utils.getNamenodeId(config, hdfs2.getUri());
testNfsGetAttrResponse(status.getFileId(), namenodeId, Nfs3Status.NFS3_OK);
}
@Test (timeout = 60000)
public void testWrongNfsAccess() throws Exception {
DFSTestUtil.createFile(viewFs, new Path("/hdfs1/file3"), 0, (short) 1, 0);
HdfsFileStatus status = nn1.getRpcServer().getFileInfo("/user1/file3");
int namenodeId = Nfs3Utils.getNamenodeId(config, hdfs2.getUri());
testNfsGetAttrResponse(status.getFileId(), namenodeId,
Nfs3Status.NFS3ERR_IO);
}
// Test for write
private void testNfsWriteResponse(long dirId, int namenodeId)
throws Exception {
FileHandle handle = new FileHandle(dirId, namenodeId);
byte[] buffer = new byte[10];
for (int i = 0; i < 10; i++) {
buffer[i] = (byte) i;
}
WRITE3Request writeReq = new WRITE3Request(handle, 0, 10,
Nfs3Constant.WriteStableHow.DATA_SYNC, ByteBuffer.wrap(buffer));
XDR xdrReq = new XDR();
writeReq.serialize(xdrReq);
// Attempt by a priviledged user should pass.
WRITE3Response response = nfsd.write(xdrReq.asReadOnlyWrap(),
null, 1, securityHandler,
new InetSocketAddress("localhost", 1234));
Assert.assertEquals("Incorrect response:", null, response);
}
@Test (timeout = 60000)
public void testNfsWriteNN1() throws Exception {
HdfsFileStatus status = nn1.getRpcServer().getFileInfo("/user1/write1");
int namenodeId = Nfs3Utils.getNamenodeId(config, hdfs1.getUri());
testNfsWriteResponse(status.getFileId(), namenodeId);
}
@Test (timeout = 60000)
public void testNfsWriteNN2() throws Exception {
HdfsFileStatus status = nn2.getRpcServer().getFileInfo("/user2/write2");
int namenodeId = Nfs3Utils.getNamenodeId(config, hdfs2.getUri());
testNfsWriteResponse(status.getFileId(), namenodeId);
}
// Test for rename
private void testNfsRename(FileHandle fromDirHandle, String fromFileName,
FileHandle toDirHandle, String toFileName,
int expectedStatus) throws Exception {
XDR xdrReq = new XDR();
RENAME3Request req = new RENAME3Request(fromDirHandle, fromFileName,
toDirHandle, toFileName);
req.serialize(xdrReq);
// Attempt by a privileged user should pass.
RENAME3Response response = nfsd.rename(xdrReq.asReadOnlyWrap(),
securityHandler, new InetSocketAddress("localhost", 1234));
assertEquals(expectedStatus, response.getStatus());
}
@Test (timeout = 60000)
public void testNfsRenameMultiNN() throws Exception {
HdfsFileStatus fromFileStatus = nn1.getRpcServer().getFileInfo("/user1");
int fromNNId = Nfs3Utils.getNamenodeId(config, hdfs1.getUri());
FileHandle fromHandle =
new FileHandle(fromFileStatus.getFileId(), fromNNId);
HdfsFileStatus toFileStatus = nn2.getRpcServer().getFileInfo("/user2");
int toNNId = Nfs3Utils.getNamenodeId(config, hdfs2.getUri());
FileHandle toHandle = new FileHandle(toFileStatus.getFileId(), toNNId);
HdfsFileStatus statusBeforeRename =
nn1.getRpcServer().getFileInfo("/user1/renameMultiNN");
Assert.assertEquals(statusBeforeRename.isDirectory(), false);
testNfsRename(fromHandle, "renameMultiNN",
toHandle, "renameMultiNNFail", Nfs3Status.NFS3ERR_INVAL);
HdfsFileStatus statusAfterRename =
nn2.getRpcServer().getFileInfo("/user2/renameMultiNNFail");
Assert.assertEquals(statusAfterRename, null);
statusAfterRename = nn1.getRpcServer().getFileInfo("/user1/renameMultiNN");
Assert.assertEquals(statusAfterRename.isDirectory(), false);
}
@Test (timeout = 60000)
public void testNfsRenameSingleNN() throws Exception {
HdfsFileStatus fromFileStatus = nn1.getRpcServer().getFileInfo("/user1");
int fromNNId = Nfs3Utils.getNamenodeId(config, hdfs1.getUri());
FileHandle fromHandle =
new FileHandle(fromFileStatus.getFileId(), fromNNId);
HdfsFileStatus statusBeforeRename =
nn1.getRpcServer().getFileInfo("/user1/renameSingleNN");
Assert.assertEquals(statusBeforeRename.isDirectory(), false);
testNfsRename(fromHandle, "renameSingleNN",
fromHandle, "renameSingleNNSucess", Nfs3Status.NFS3_OK);
HdfsFileStatus statusAfterRename =
nn1.getRpcServer().getFileInfo("/user1/renameSingleNNSucess");
Assert.assertEquals(statusAfterRename.isDirectory(), false);
statusAfterRename =
nn1.getRpcServer().getFileInfo("/user1/renameSingleNN");
Assert.assertEquals(statusAfterRename, null);
}
}