blob: fa6b62cadd9ae60d0744a0d041fb7044b0637ef2 [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.server.federation.router;
import static org.apache.hadoop.fs.permission.FsAction.ALL;
import static org.apache.hadoop.fs.permission.FsAction.READ_EXECUTE;
import static org.apache.hadoop.hdfs.server.federation.FederationTestUtils.verifyFileExists;
import static org.apache.hadoop.test.GenericTestUtils.getMethodName;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.io.IOException;
import java.util.List;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.AclEntry;
import org.apache.hadoop.fs.permission.FsAction;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.fs.permission.AclEntryScope;
import org.apache.hadoop.fs.permission.AclEntryType;
import org.apache.hadoop.hdfs.DFSClient;
import org.apache.hadoop.hdfs.protocol.ClientProtocol;
import org.apache.hadoop.hdfs.server.federation.MiniRouterDFSCluster;
import org.apache.hadoop.hdfs.server.federation.resolver.RemoteLocation;
import org.apache.hadoop.ipc.RemoteException;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.test.LambdaTestUtils;
import org.apache.hadoop.util.Lists;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
/**
* Test permission check of router federation rename.
*/
public class TestRouterFederationRenamePermission
extends TestRouterFederationRenameBase {
private String srcNs; // the source namespace.
private String dstNs; // the dst namespace.
// the source path.
private String srcStr;
private Path srcPath;
// the dst path.
private String dstStr;
private Path dstPath;
private UserGroupInformation foo;
private MiniRouterDFSCluster.RouterContext router;
private FileSystem routerFS;
private MiniRouterDFSCluster cluster;
@BeforeClass
public static void before() throws Exception {
globalSetUp();
}
@AfterClass
public static void after() {
tearDown();
}
@Before
public void testSetup() throws Exception {
setup();
cluster = getCluster();
List<String> nss = cluster.getNameservices();
srcNs = nss.get(0);
dstNs = nss.get(1);
srcStr = cluster.getFederatedTestDirectoryForNS(srcNs) + "/d0/"
+ getMethodName();
dstStr = cluster.getFederatedTestDirectoryForNS(dstNs) + "/d0/"
+ getMethodName();
srcPath = new Path(srcStr);
dstPath = new Path(dstStr);
foo = UserGroupInformation.createRemoteUser("foo");
router = getRouterContext();
routerFS = getRouterFileSystem();
}
@Test
public void testRenameSnapshotPath() throws Exception {
LambdaTestUtils.intercept(IOException.class,
"Router federation rename can't rename snapshot path",
"Expect IOException.", () -> RouterFederationRename.checkSnapshotPath(
new RemoteLocation(srcNs, "/foo/.snapshot/src", "/src"),
new RemoteLocation(dstNs, "/foo/dst", "/dst")));
LambdaTestUtils.intercept(IOException.class,
"Router federation rename can't rename snapshot path",
"Expect IOException.", () -> RouterFederationRename
.checkSnapshotPath(new RemoteLocation(srcNs, "/foo/src", "/src"),
new RemoteLocation(dstNs, "/foo/.snapshot/dst", "/dst")));
}
// Case1: the source path doesn't exist.
@Test
public void testPermission1() throws Exception {
LambdaTestUtils.intercept(RemoteException.class, "FileNotFoundException",
"Expect FileNotFoundException.", () -> {
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
});
}
// Case2: the source path parent without any permission.
@Test
public void testPermission2() throws Exception {
createDir(routerFS, srcStr);
routerFS.setPermission(srcPath.getParent(),
FsPermission.createImmutable((short) 0));
LambdaTestUtils.intercept(RemoteException.class, "AccessControlException",
"Expect AccessControlException.", () -> {
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
});
}
// Case3: the source path with rwxr-xr-x permission.
@Test
public void testPermission3() throws Exception {
createDir(routerFS, srcStr);
routerFS.setPermission(srcPath.getParent(),
FsPermission.createImmutable((short) 493));
LambdaTestUtils.intercept(RemoteException.class, "AccessControlException",
"Expect AccessControlException.", () -> {
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
});
}
// Case4: the source path with unrelated acl user:not-foo:rwx.
@Test
public void testPermission4() throws Exception {
createDir(routerFS, srcStr);
routerFS.setAcl(srcPath.getParent(), buildAcl("not-foo", ALL));
LambdaTestUtils.intercept(RemoteException.class, "AccessControlException",
"Expect AccessControlException.", () -> {
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
});
}
// Case5: the source path with user:foo:rwx. And the dst path doesn't exist.
@Test
public void testPermission5() throws Exception {
createDir(routerFS, srcStr);
routerFS.setAcl(srcPath.getParent(), buildAcl("foo", ALL));
assertFalse(routerFS.exists(dstPath.getParent()));
LambdaTestUtils.intercept(RemoteException.class, "FileNotFoundException",
"Expect FileNotFoundException.", () -> {
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
});
}
// Case6: the src path with correct permission and the dst path with bad
// permission.
@Test
public void testPermission6() throws Exception {
createDir(routerFS, srcStr);
routerFS.setAcl(srcPath.getParent(), buildAcl("foo", ALL));
assertTrue(routerFS.mkdirs(dstPath.getParent()));
LambdaTestUtils.intercept(RemoteException.class, "AccessControlException",
"Expect AccessControlException.", () -> {
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
});
}
// Case7: successful rename.
@Test
public void testPermission7() throws Exception {
createDir(routerFS, srcStr);
routerFS.setAcl(srcPath.getParent(), buildAcl("foo", ALL));
assertTrue(routerFS.mkdirs(dstPath.getParent()));
routerFS.setOwner(dstPath.getParent(), "foo", "foogroup");
DFSClient client = router.getClient(foo);
ClientProtocol clientProtocol = client.getNamenode();
clientProtocol.rename(srcStr, dstStr);
assertFalse(verifyFileExists(routerFS, srcStr));
assertTrue(
verifyFileExists(routerFS, dstStr + "/file"));
}
/**
* Build acl list.
*
* user::rwx
* group::rwx
* user:input_user:input_permission
* other::r-x
* @param user the input user.
* @param permission the input fs action.
*/
private List<AclEntry> buildAcl(String user, FsAction permission) {
List<AclEntry> aclEntryList = Lists.newArrayList();
aclEntryList.add(
new AclEntry.Builder()
.setName(user)
.setPermission(permission)
.setScope(AclEntryScope.ACCESS)
.setType(AclEntryType.USER)
.build());
aclEntryList.add(
new AclEntry.Builder()
.setPermission(FsAction.ALL)
.setScope(AclEntryScope.ACCESS)
.setType(AclEntryType.USER)
.build());
aclEntryList.add(
new AclEntry.Builder()
.setPermission(FsAction.ALL)
.setScope(AclEntryScope.ACCESS)
.setType(AclEntryType.GROUP)
.build());
aclEntryList.add(
new AclEntry.Builder()
.setPermission(READ_EXECUTE)
.setScope(AclEntryScope.ACCESS)
.setType(AclEntryType.OTHER)
.build());
return aclEntryList;
}
}