org.apache.hadoop.hdfs.TestFsShellPermission.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hdfs.TestFsShellPermission.java

Source

/**
 * 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;

import static org.junit.Assert.assertEquals;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.URI;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Arrays;

import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.FileSystemTestHelper;
import org.apache.hadoop.fs.FsShell;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.security.UserGroupInformation;
import org.junit.Test;

/**
 * This test covers privilege related aspects of FsShell
 *
 */
public class TestFsShellPermission {

    static private final String TEST_ROOT = "/testroot";

    static UserGroupInformation createUGI(String ownername, String groupName) {
        return UserGroupInformation.createUserForTesting(ownername, new String[] { groupName });
    }

    private class FileEntry {
        private String path;
        private boolean isDir;
        private String owner;
        private String group;
        private String permission;

        public FileEntry(String path, boolean isDir, String owner, String group, String permission) {
            this.path = path;
            this.isDir = isDir;
            this.owner = owner;
            this.group = group;
            this.permission = permission;
        }

        String getPath() {
            return path;
        }

        boolean isDirectory() {
            return isDir;
        }

        String getOwner() {
            return owner;
        }

        String getGroup() {
            return group;
        }

        String getPermission() {
            return permission;
        }
    }

    private void createFiles(FileSystem fs, String topdir, FileEntry[] entries) throws IOException {
        for (FileEntry entry : entries) {
            String newPathStr = topdir + "/" + entry.getPath();
            Path newPath = new Path(newPathStr);
            if (entry.isDirectory()) {
                fs.mkdirs(newPath);
            } else {
                FileSystemTestHelper.createFile(fs, newPath);
            }
            fs.setPermission(newPath, new FsPermission(entry.getPermission()));
            fs.setOwner(newPath, entry.getOwner(), entry.getGroup());
        }
    }

    /** delete directory and everything underneath it.*/
    private static void deldir(FileSystem fs, String topdir) throws IOException {
        fs.delete(new Path(topdir), true);
    }

    static String execCmd(FsShell shell, final String[] args) throws Exception {
        ByteArrayOutputStream baout = new ByteArrayOutputStream();
        PrintStream out = new PrintStream(baout, true);
        PrintStream old = System.out;
        System.setOut(out);
        int ret = shell.run(args);
        out.close();
        System.setOut(old);
        return String.valueOf(ret);
    }

    /*
     * Each instance of TestDeleteHelper captures one testing scenario.
     *
     * To create all files listed in fileEntries, and then delete as user
     * doAsuser the deleteEntry with command+options specified in cmdAndOptions.
     *
     * When expectedToDelete is true, the deleteEntry is expected to be deleted;
     * otherwise, it's not expected to be deleted. At the end of test,
     * the existence of deleteEntry is checked against expectedToDelete
     * to ensure the command is finished with expected result
     */
    private class TestDeleteHelper {
        private FileEntry[] fileEntries;
        private FileEntry deleteEntry;
        private String cmdAndOptions;
        private boolean expectedToDelete;

        final String doAsGroup;
        final UserGroupInformation userUgi;

        public TestDeleteHelper(FileEntry[] fileEntries, FileEntry deleteEntry, String cmdAndOptions,
                String doAsUser, boolean expectedToDelete) {
            this.fileEntries = fileEntries;
            this.deleteEntry = deleteEntry;
            this.cmdAndOptions = cmdAndOptions;
            this.expectedToDelete = expectedToDelete;

            doAsGroup = doAsUser.equals("hdfs") ? "supergroup" : "users";
            userUgi = createUGI(doAsUser, doAsGroup);
        }

        public void execute(Configuration conf, FileSystem fs) throws Exception {
            fs.mkdirs(new Path(TEST_ROOT));

            createFiles(fs, TEST_ROOT, fileEntries);
            final FsShell fsShell = new FsShell(conf);
            final String deletePath = TEST_ROOT + "/" + deleteEntry.getPath();

            String[] tmpCmdOpts = StringUtils.split(cmdAndOptions);
            ArrayList<String> tmpArray = new ArrayList<String>(Arrays.asList(tmpCmdOpts));
            tmpArray.add(deletePath);
            final String[] cmdOpts = tmpArray.toArray(new String[tmpArray.size()]);
            userUgi.doAs(new PrivilegedExceptionAction<String>() {
                public String run() throws Exception {
                    return execCmd(fsShell, cmdOpts);
                }
            });

            boolean deleted = !fs.exists(new Path(deletePath));
            assertEquals(expectedToDelete, deleted);

            deldir(fs, TEST_ROOT);
        }
    }

    private TestDeleteHelper genDeleteEmptyDirHelper(final String cmdOpts, final String targetPerm,
            final String asUser, boolean expectedToDelete) {
        FileEntry[] files = { new FileEntry("userA", true, "userA", "users", "755"),
                new FileEntry("userA/userB", true, "userB", "users", targetPerm) };
        FileEntry deleteEntry = files[1];
        return new TestDeleteHelper(files, deleteEntry, cmdOpts, asUser, expectedToDelete);
    }

    // Expect target to be deleted
    private TestDeleteHelper genRmrEmptyDirWithReadPerm() {
        return genDeleteEmptyDirHelper("-rm -r", "744", "userA", true);
    }

    // Expect target to be deleted
    private TestDeleteHelper genRmrEmptyDirWithNoPerm() {
        return genDeleteEmptyDirHelper("-rm -r", "700", "userA", true);
    }

    // Expect target to be deleted
    private TestDeleteHelper genRmrfEmptyDirWithNoPerm() {
        return genDeleteEmptyDirHelper("-rm -r -f", "700", "userA", true);
    }

    private TestDeleteHelper genDeleteNonEmptyDirHelper(final String cmd, final String targetPerm,
            final String asUser, boolean expectedToDelete) {
        FileEntry[] files = { new FileEntry("userA", true, "userA", "users", "755"),
                new FileEntry("userA/userB", true, "userB", "users", targetPerm),
                new FileEntry("userA/userB/xyzfile", false, "userB", "users", targetPerm) };
        FileEntry deleteEntry = files[1];
        return new TestDeleteHelper(files, deleteEntry, cmd, asUser, expectedToDelete);
    }

    // Expect target not to be deleted
    private TestDeleteHelper genRmrNonEmptyDirWithReadPerm() {
        return genDeleteNonEmptyDirHelper("-rm -r", "744", "userA", false);
    }

    // Expect target not to be deleted
    private TestDeleteHelper genRmrNonEmptyDirWithNoPerm() {
        return genDeleteNonEmptyDirHelper("-rm -r", "700", "userA", false);
    }

    // Expect target to be deleted
    private TestDeleteHelper genRmrNonEmptyDirWithAllPerm() {
        return genDeleteNonEmptyDirHelper("-rm -r", "777", "userA", true);
    }

    // Expect target not to be deleted
    private TestDeleteHelper genRmrfNonEmptyDirWithNoPerm() {
        return genDeleteNonEmptyDirHelper("-rm -r -f", "700", "userA", false);
    }

    // Expect target to be deleted
    public TestDeleteHelper genDeleteSingleFileNotAsOwner() throws Exception {
        FileEntry[] files = { new FileEntry("userA", true, "userA", "users", "755"),
                new FileEntry("userA/userB", false, "userB", "users", "700") };
        FileEntry deleteEntry = files[1];
        return new TestDeleteHelper(files, deleteEntry, "-rm -r", "userA", true);
    }

    @Test
    public void testDelete() throws Exception {
        Configuration conf = null;
        MiniDFSCluster cluster = null;
        try {
            conf = new Configuration();
            cluster = new MiniDFSCluster.Builder(conf).numDataNodes(2).build();

            String nnUri = FileSystem.getDefaultUri(conf).toString();
            FileSystem fs = FileSystem.get(URI.create(nnUri), conf);

            ArrayList<TestDeleteHelper> ta = new ArrayList<TestDeleteHelper>();

            // Add empty dir tests
            ta.add(genRmrEmptyDirWithReadPerm());
            //      ta.add(genRmrEmptyDirWithNoPerm());
            //      ta.add(genRmrfEmptyDirWithNoPerm());

            // Add non-empty dir tests
            //      ta.add(genRmrNonEmptyDirWithReadPerm());
            //      ta.add(genRmrNonEmptyDirWithNoPerm());
            //      ta.add(genRmrNonEmptyDirWithAllPerm());
            //      ta.add(genRmrfNonEmptyDirWithNoPerm());

            // Add single tile test
            //      ta.add(genDeleteSingleFileNotAsOwner());

            // Run all tests
            for (TestDeleteHelper t : ta) {
                t.execute(conf, fs);
            }
        } finally {
            if (cluster != null) {
                cluster.shutdown();
            }
        }
    }
}