HBASE-12552 listSnapshots should list only owned snapshots for non-super user

This commit is contained in:
tedyu 2014-11-21 10:54:05 -08:00
parent 325cdc0987
commit 890c067b66
7 changed files with 116 additions and 5 deletions

View File

@ -372,6 +372,16 @@ public abstract class BaseMasterAndRegionObserver extends BaseRegionObserver
throws IOException {
}
@Override
public void preListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
}
@Override
public void postListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
}
@Override
public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)

View File

@ -365,6 +365,16 @@ public class BaseMasterObserver implements MasterObserver {
throws IOException {
}
@Override
public void preListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
}
@Override
public void postListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
}
@Override
public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)

View File

@ -597,6 +597,26 @@ public interface MasterObserver extends Coprocessor {
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
throws IOException;
/**
* Called before listSnapshots request has been processed.
* It can't bypass the default action, e.g., ctx.bypass() won't have effect.
* @param ctx the environment to interact with the framework and master
* @param snapshot the SnapshotDescriptor of the snapshot to list
* @throws IOException
*/
void preListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException;
/**
* Called after listSnapshots request has been processed.
* It can't bypass the default action, e.g., ctx.bypass() won't have effect.
* @param ctx the environment to interact with the framework and master
* @param snapshot the SnapshotDescriptor of the snapshot to list
* @throws IOException
*/
void postListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException;
/**
* Called before a snapshot is cloned.
* Called as part of restoreSnapshot RPC call.

View File

@ -727,6 +727,26 @@ public class MasterCoprocessorHost
});
}
public void preListSnapshot(final SnapshotDescription snapshot) throws IOException {
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
@Override
public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
throws IOException {
observer.preListSnapshot(ctx, snapshot);
}
});
}
public void postListSnapshot(final SnapshotDescription snapshot) throws IOException {
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {
@Override
public void call(MasterObserver observer, ObserverContext<MasterCoprocessorEnvironment> ctx)
throws IOException {
observer.postListSnapshot(ctx, snapshot);
}
});
}
public void preCloneSnapshot(final SnapshotDescription snapshot,
final HTableDescriptor hTableDescriptor) throws IOException {
execOperation(coprocessors.isEmpty() ? null : new CoprocessorOperation() {

View File

@ -31,19 +31,19 @@ import java.util.concurrent.ThreadPoolExecutor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileStatus;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.HBaseInterfaceAudience;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.Stoppable;
import org.apache.hadoop.hbase.MetaTableAccessor;
import org.apache.hadoop.hbase.Stoppable;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.hbase.client.TableState;
import org.apache.hadoop.hbase.errorhandling.ForeignException;
import org.apache.hadoop.hbase.executor.ExecutorService;
@ -65,7 +65,7 @@ import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.NameStringPair;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ProcedureDescription;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription.Type;
import org.apache.hadoop.hbase.protobuf.generated.ZooKeeperProtos;
import org.apache.hadoop.hbase.security.AccessDeniedException;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
@ -214,6 +214,7 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
// ignore all the snapshots in progress
FileStatus[] snapshots = fs.listStatus(snapshotDir,
new SnapshotDescriptionUtils.CompletedSnaphotDirectoriesFilter(fs));
MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost();
// loop through all the completed snapshots
for (FileStatus snapshot : snapshots) {
Path info = new Path(snapshot.getPath(), SnapshotDescriptionUtils.SNAPSHOTINFO_FILE);
@ -226,7 +227,22 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
try {
in = fs.open(info);
SnapshotDescription desc = SnapshotDescription.parseFrom(in);
if (cpHost != null) {
try {
cpHost.preListSnapshot(desc);
} catch (AccessDeniedException e) {
LOG.warn("Current user does not have access to " + desc.getName() + " snapshot. "
+ "Either you should be owner of this snapshot or admin user.");
// Skip this and try for next snapshot
continue;
}
}
snapshotDescs.add(desc);
// call coproc post hook
if (cpHost != null) {
cpHost.postListSnapshot(desc);
}
} catch (IOException e) {
LOG.warn("Found a corrupted snapshot " + snapshot.getPath(), e);
} finally {

View File

@ -1103,6 +1103,16 @@ public class AccessController extends BaseMasterAndRegionObserver
Permission.Action.ADMIN);
}
@Override
public void preListSnapshot(ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, getActiveUser())) {
// list it, if user is the owner of snapshot
} else {
requirePermission("listSnapshot", Action.ADMIN);
}
}
@Override
public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)

View File

@ -122,6 +122,8 @@ public class TestMasterObserver {
private boolean stopCalled;
private boolean preSnapshotCalled;
private boolean postSnapshotCalled;
private boolean preListSnapshotCalled;
private boolean postListSnapshotCalled;
private boolean preCloneSnapshotCalled;
private boolean postCloneSnapshotCalled;
private boolean preRestoreSnapshotCalled;
@ -192,6 +194,8 @@ public class TestMasterObserver {
postBalanceSwitchCalled = false;
preSnapshotCalled = false;
postSnapshotCalled = false;
preListSnapshotCalled = false;
postListSnapshotCalled = false;
preCloneSnapshotCalled = false;
postCloneSnapshotCalled = false;
preRestoreSnapshotCalled = false;
@ -705,6 +709,22 @@ public class TestMasterObserver {
return preSnapshotCalled && postSnapshotCalled;
}
@Override
public void preListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
preListSnapshotCalled = true;
}
@Override
public void postListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
postListSnapshotCalled = true;
}
public boolean wasListSnapshotCalled() {
return preListSnapshotCalled && postListSnapshotCalled;
}
@Override
public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
@ -1315,6 +1335,11 @@ public class TestMasterObserver {
assertTrue("Coprocessor should have been called on snapshot",
cp.wasSnapshotCalled());
//Test list operation
admin.listSnapshots();
assertTrue("Coprocessor should have been called on snapshot list",
cp.wasListSnapshotCalled());
// Test clone operation
admin.cloneSnapshot(TEST_SNAPSHOT, TEST_CLONE);
assertTrue("Coprocessor should have been called on snapshot clone",