You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by dd...@apache.org on 2015/04/02 08:57:08 UTC
hbase git commit: HBASE-11869. Support snapshot owner (Liu Shaohui).
Repository: hbase
Updated Branches:
refs/heads/branch-1 1dfcbdf5e -> 926aaed11
HBASE-11869. Support snapshot owner (Liu Shaohui).
Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/926aaed1
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/926aaed1
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/926aaed1
Branch: refs/heads/branch-1
Commit: 926aaed11356922a481535a109626e3305a5630d
Parents: 1dfcbdf
Author: Devaraj Das <dd...@apache.org>
Authored: Wed Apr 1 23:56:59 2015 -0700
Committer: Devaraj Das <dd...@apache.org>
Committed: Wed Apr 1 23:56:59 2015 -0700
----------------------------------------------------------------------
.../hbase/protobuf/generated/HBaseProtos.java | 204 +++++++++++++++++--
hbase-protocol/src/main/protobuf/HBase.proto | 1 +
.../hbase/master/snapshot/SnapshotManager.java | 55 ++---
.../hbase/security/access/AccessController.java | 17 +-
.../snapshot/SnapshotDescriptionUtils.java | 14 ++
.../security/access/TestAccessController.java | 73 ++++++-
6 files changed, 314 insertions(+), 50 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/hbase/blob/926aaed1/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java
index 1dbce4d..dd55599 100644
--- a/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java
+++ b/hbase-protocol/src/main/java/org/apache/hadoop/hbase/protobuf/generated/HBaseProtos.java
@@ -10426,6 +10426,21 @@ public final class HBaseProtos {
* <code>optional int32 version = 5;</code>
*/
int getVersion();
+
+ // optional string owner = 6;
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ boolean hasOwner();
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ java.lang.String getOwner();
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ com.google.protobuf.ByteString
+ getOwnerBytes();
}
/**
* Protobuf type {@code SnapshotDescription}
@@ -10514,6 +10529,11 @@ public final class HBaseProtos {
version_ = input.readInt32();
break;
}
+ case 50: {
+ bitField0_ |= 0x00000020;
+ owner_ = input.readBytes();
+ break;
+ }
}
}
} catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -10791,12 +10811,56 @@ public final class HBaseProtos {
return version_;
}
+ // optional string owner = 6;
+ public static final int OWNER_FIELD_NUMBER = 6;
+ private java.lang.Object owner_;
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public boolean hasOwner() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public java.lang.String getOwner() {
+ java.lang.Object ref = owner_;
+ if (ref instanceof java.lang.String) {
+ return (java.lang.String) ref;
+ } else {
+ com.google.protobuf.ByteString bs =
+ (com.google.protobuf.ByteString) ref;
+ java.lang.String s = bs.toStringUtf8();
+ if (bs.isValidUtf8()) {
+ owner_ = s;
+ }
+ return s;
+ }
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public com.google.protobuf.ByteString
+ getOwnerBytes() {
+ java.lang.Object ref = owner_;
+ if (ref instanceof java.lang.String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ owner_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+
private void initFields() {
name_ = "";
table_ = "";
creationTime_ = 0L;
type_ = org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription.Type.FLUSH;
version_ = 0;
+ owner_ = "";
}
private byte memoizedIsInitialized = -1;
public final boolean isInitialized() {
@@ -10829,6 +10893,9 @@ public final class HBaseProtos {
if (((bitField0_ & 0x00000010) == 0x00000010)) {
output.writeInt32(5, version_);
}
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ output.writeBytes(6, getOwnerBytes());
+ }
getUnknownFields().writeTo(output);
}
@@ -10858,6 +10925,10 @@ public final class HBaseProtos {
size += com.google.protobuf.CodedOutputStream
.computeInt32Size(5, version_);
}
+ if (((bitField0_ & 0x00000020) == 0x00000020)) {
+ size += com.google.protobuf.CodedOutputStream
+ .computeBytesSize(6, getOwnerBytes());
+ }
size += getUnknownFields().getSerializedSize();
memoizedSerializedSize = size;
return size;
@@ -10906,6 +10977,11 @@ public final class HBaseProtos {
result = result && (getVersion()
== other.getVersion());
}
+ result = result && (hasOwner() == other.hasOwner());
+ if (hasOwner()) {
+ result = result && getOwner()
+ .equals(other.getOwner());
+ }
result = result &&
getUnknownFields().equals(other.getUnknownFields());
return result;
@@ -10939,6 +11015,10 @@ public final class HBaseProtos {
hash = (37 * hash) + VERSION_FIELD_NUMBER;
hash = (53 * hash) + getVersion();
}
+ if (hasOwner()) {
+ hash = (37 * hash) + OWNER_FIELD_NUMBER;
+ hash = (53 * hash) + getOwner().hashCode();
+ }
hash = (29 * hash) + getUnknownFields().hashCode();
memoizedHashCode = hash;
return hash;
@@ -11063,6 +11143,8 @@ public final class HBaseProtos {
bitField0_ = (bitField0_ & ~0x00000008);
version_ = 0;
bitField0_ = (bitField0_ & ~0x00000010);
+ owner_ = "";
+ bitField0_ = (bitField0_ & ~0x00000020);
return this;
}
@@ -11111,6 +11193,10 @@ public final class HBaseProtos {
to_bitField0_ |= 0x00000010;
}
result.version_ = version_;
+ if (((from_bitField0_ & 0x00000020) == 0x00000020)) {
+ to_bitField0_ |= 0x00000020;
+ }
+ result.owner_ = owner_;
result.bitField0_ = to_bitField0_;
onBuilt();
return result;
@@ -11146,6 +11232,11 @@ public final class HBaseProtos {
if (other.hasVersion()) {
setVersion(other.getVersion());
}
+ if (other.hasOwner()) {
+ bitField0_ |= 0x00000020;
+ owner_ = other.owner_;
+ onChanged();
+ }
this.mergeUnknownFields(other.getUnknownFields());
return this;
}
@@ -11451,6 +11542,80 @@ public final class HBaseProtos {
return this;
}
+ // optional string owner = 6;
+ private java.lang.Object owner_ = "";
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public boolean hasOwner() {
+ return ((bitField0_ & 0x00000020) == 0x00000020);
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public java.lang.String getOwner() {
+ java.lang.Object ref = owner_;
+ if (!(ref instanceof java.lang.String)) {
+ java.lang.String s = ((com.google.protobuf.ByteString) ref)
+ .toStringUtf8();
+ owner_ = s;
+ return s;
+ } else {
+ return (java.lang.String) ref;
+ }
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public com.google.protobuf.ByteString
+ getOwnerBytes() {
+ java.lang.Object ref = owner_;
+ if (ref instanceof String) {
+ com.google.protobuf.ByteString b =
+ com.google.protobuf.ByteString.copyFromUtf8(
+ (java.lang.String) ref);
+ owner_ = b;
+ return b;
+ } else {
+ return (com.google.protobuf.ByteString) ref;
+ }
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public Builder setOwner(
+ java.lang.String value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000020;
+ owner_ = value;
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public Builder clearOwner() {
+ bitField0_ = (bitField0_ & ~0x00000020);
+ owner_ = getDefaultInstance().getOwner();
+ onChanged();
+ return this;
+ }
+ /**
+ * <code>optional string owner = 6;</code>
+ */
+ public Builder setOwnerBytes(
+ com.google.protobuf.ByteString value) {
+ if (value == null) {
+ throw new NullPointerException();
+ }
+ bitField0_ |= 0x00000020;
+ owner_ = value;
+ onChanged();
+ return this;
+ }
+
// @@protoc_insertion_point(builder_scope:SnapshotDescription)
}
@@ -16341,26 +16506,27 @@ public final class HBaseProtos {
"\014\n\004name\030\001 \002(\t\022\r\n\005value\030\002 \001(\014\"/\n\016BytesByt" +
"esPair\022\r\n\005first\030\001 \002(\014\022\016\n\006second\030\002 \002(\014\",\n" +
"\rNameInt64Pair\022\014\n\004name\030\001 \001(\t\022\r\n\005value\030\002 " +
- "\001(\003\"\275\001\n\023SnapshotDescription\022\014\n\004name\030\001 \002(" +
+ "\001(\003\"\314\001\n\023SnapshotDescription\022\014\n\004name\030\001 \002(" +
"\t\022\r\n\005table\030\002 \001(\t\022\030\n\rcreation_time\030\003 \001(\003:" +
"\0010\022.\n\004type\030\004 \001(\0162\031.SnapshotDescription.T" +
- "ype:\005FLUSH\022\017\n\007version\030\005 \001(\005\".\n\004Type\022\014\n\010D",
- "ISABLED\020\000\022\t\n\005FLUSH\020\001\022\r\n\tSKIPFLUSH\020\002\"}\n\024P" +
- "rocedureDescription\022\021\n\tsignature\030\001 \002(\t\022\020" +
- "\n\010instance\030\002 \001(\t\022\030\n\rcreation_time\030\003 \001(\003:" +
- "\0010\022&\n\rconfiguration\030\004 \003(\0132\017.NameStringPa" +
- "ir\"\n\n\010EmptyMsg\"\033\n\007LongMsg\022\020\n\010long_msg\030\001 " +
- "\002(\003\"\037\n\tDoubleMsg\022\022\n\ndouble_msg\030\001 \002(\001\"\'\n\r" +
- "BigDecimalMsg\022\026\n\016bigdecimal_msg\030\001 \002(\014\"5\n" +
- "\004UUID\022\026\n\016least_sig_bits\030\001 \002(\004\022\025\n\rmost_si" +
- "g_bits\030\002 \002(\004\"K\n\023NamespaceDescriptor\022\014\n\004n" +
- "ame\030\001 \002(\014\022&\n\rconfiguration\030\002 \003(\0132\017.NameS",
- "tringPair\"$\n\020RegionServerInfo\022\020\n\010infoPor" +
- "t\030\001 \001(\005*r\n\013CompareType\022\010\n\004LESS\020\000\022\021\n\rLESS" +
- "_OR_EQUAL\020\001\022\t\n\005EQUAL\020\002\022\r\n\tNOT_EQUAL\020\003\022\024\n" +
- "\020GREATER_OR_EQUAL\020\004\022\013\n\007GREATER\020\005\022\t\n\005NO_O" +
- "P\020\006B>\n*org.apache.hadoop.hbase.protobuf." +
- "generatedB\013HBaseProtosH\001\240\001\001"
+ "ype:\005FLUSH\022\017\n\007version\030\005 \001(\005\022\r\n\005owner\030\006 \001",
+ "(\t\".\n\004Type\022\014\n\010DISABLED\020\000\022\t\n\005FLUSH\020\001\022\r\n\tS" +
+ "KIPFLUSH\020\002\"}\n\024ProcedureDescription\022\021\n\tsi" +
+ "gnature\030\001 \002(\t\022\020\n\010instance\030\002 \001(\t\022\030\n\rcreat" +
+ "ion_time\030\003 \001(\003:\0010\022&\n\rconfiguration\030\004 \003(\013" +
+ "2\017.NameStringPair\"\n\n\010EmptyMsg\"\033\n\007LongMsg" +
+ "\022\020\n\010long_msg\030\001 \002(\003\"\037\n\tDoubleMsg\022\022\n\ndoubl" +
+ "e_msg\030\001 \002(\001\"\'\n\rBigDecimalMsg\022\026\n\016bigdecim" +
+ "al_msg\030\001 \002(\014\"5\n\004UUID\022\026\n\016least_sig_bits\030\001" +
+ " \002(\004\022\025\n\rmost_sig_bits\030\002 \002(\004\"K\n\023Namespace" +
+ "Descriptor\022\014\n\004name\030\001 \002(\014\022&\n\rconfiguratio",
+ "n\030\002 \003(\0132\017.NameStringPair\"$\n\020RegionServer" +
+ "Info\022\020\n\010infoPort\030\001 \001(\005*r\n\013CompareType\022\010\n" +
+ "\004LESS\020\000\022\021\n\rLESS_OR_EQUAL\020\001\022\t\n\005EQUAL\020\002\022\r\n" +
+ "\tNOT_EQUAL\020\003\022\024\n\020GREATER_OR_EQUAL\020\004\022\013\n\007GR" +
+ "EATER\020\005\022\t\n\005NO_OP\020\006B>\n*org.apache.hadoop." +
+ "hbase.protobuf.generatedB\013HBaseProtosH\001\240" +
+ "\001\001"
};
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -16450,7 +16616,7 @@ public final class HBaseProtos {
internal_static_SnapshotDescription_fieldAccessorTable = new
com.google.protobuf.GeneratedMessage.FieldAccessorTable(
internal_static_SnapshotDescription_descriptor,
- new java.lang.String[] { "Name", "Table", "CreationTime", "Type", "Version", });
+ new java.lang.String[] { "Name", "Table", "CreationTime", "Type", "Version", "Owner", });
internal_static_ProcedureDescription_descriptor =
getDescriptor().getMessageTypes().get(14);
internal_static_ProcedureDescription_fieldAccessorTable = new
http://git-wip-us.apache.org/repos/asf/hbase/blob/926aaed1/hbase-protocol/src/main/protobuf/HBase.proto
----------------------------------------------------------------------
diff --git a/hbase-protocol/src/main/protobuf/HBase.proto b/hbase-protocol/src/main/protobuf/HBase.proto
index 24941ff..ca09777 100644
--- a/hbase-protocol/src/main/protobuf/HBase.proto
+++ b/hbase-protocol/src/main/protobuf/HBase.proto
@@ -164,6 +164,7 @@ message SnapshotDescription {
}
optional Type type = 4 [default = FLUSH];
optional int32 version = 5;
+ optional string owner = 6;
}
/**
http://git-wip-us.apache.org/repos/asf/hbase/blob/926aaed1/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.java
index 44435a2..a1b756e 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/master/snapshot/SnapshotManager.java
@@ -46,6 +46,7 @@ import org.apache.hadoop.hbase.Stoppable;
import org.apache.hadoop.hbase.MetaTableAccessor;
import org.apache.hadoop.hbase.errorhandling.ForeignException;
import org.apache.hadoop.hbase.executor.ExecutorService;
+import org.apache.hadoop.hbase.ipc.RequestContext;
import org.apache.hadoop.hbase.master.AssignmentManager;
import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
import org.apache.hadoop.hbase.master.MasterFileSystem;
@@ -64,6 +65,7 @@ import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.ProcedureDescripti
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.User;
import org.apache.hadoop.hbase.snapshot.ClientSnapshotDescriptionUtils;
import org.apache.hadoop.hbase.snapshot.HBaseSnapshotException;
import org.apache.hadoop.hbase.snapshot.RestoreSnapshotException;
@@ -258,26 +260,28 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
* @throws IOException For filesystem IOExceptions
*/
public void deleteSnapshot(SnapshotDescription snapshot) throws SnapshotDoesNotExistException, IOException {
-
- // call coproc pre hook
- MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost();
- if (cpHost != null) {
- cpHost.preDeleteSnapshot(snapshot);
- }
-
// check to see if it is completed
if (!isSnapshotCompleted(snapshot)) {
throw new SnapshotDoesNotExistException(snapshot);
}
String snapshotName = snapshot.getName();
- LOG.debug("Deleting snapshot: " + snapshotName);
// first create the snapshot description and check to see if it exists
- MasterFileSystem fs = master.getMasterFileSystem();
+ FileSystem fs = master.getMasterFileSystem().getFileSystem();
Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
+ // Get snapshot info from file system. The one passed as parameter is a "fake" snapshotInfo with
+ // just the "name" and it does not contains the "real" snapshot information
+ snapshot = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
+ // call coproc pre hook
+ MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost();
+ if (cpHost != null) {
+ cpHost.preDeleteSnapshot(snapshot);
+ }
+
+ LOG.debug("Deleting snapshot: " + snapshotName);
// delete the existing snapshot
- if (!fs.getFileSystem().delete(snapshotDir, true)) {
+ if (!fs.delete(snapshotDir, true)) {
throw new HBaseSnapshotException("Failed to delete snapshot directory: " + snapshotDir);
}
@@ -541,13 +545,16 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
throw new SnapshotCreationException("Table '" + snapshot.getTable()
+ "' doesn't exist, can't take snapshot.", snapshot);
}
-
+ SnapshotDescription.Builder builder = snapshot.toBuilder();
// if not specified, set the snapshot format
if (!snapshot.hasVersion()) {
- snapshot = snapshot.toBuilder()
- .setVersion(SnapshotDescriptionUtils.SNAPSHOT_LAYOUT_VERSION)
- .build();
+ builder.setVersion(SnapshotDescriptionUtils.SNAPSHOT_LAYOUT_VERSION);
+ }
+ User user = RequestContext.getRequestUser();
+ if (User.isHBaseSecurityEnabled(master.getConfiguration()) && user != null) {
+ builder.setOwner(user.getShortName());
}
+ snapshot = builder.build();
// call pre coproc hook
MasterCoprocessorHost cpHost = master.getMasterCoprocessorHost();
@@ -681,10 +688,12 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
throw new SnapshotDoesNotExistException(reqSnapshot);
}
- // read snapshot information
- SnapshotDescription fsSnapshot = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
+ // Get snapshot info from file system. The reqSnapshot is a "fake" snapshotInfo with
+ // just the snapshot "name" and table name to restore. It does not contains the "real" snapshot
+ // information.
+ SnapshotDescription snapshot = SnapshotDescriptionUtils.readSnapshotInfo(fs, snapshotDir);
SnapshotManifest manifest = SnapshotManifest.open(master.getConfiguration(), fs,
- snapshotDir, fsSnapshot);
+ snapshotDir, snapshot);
HTableDescriptor snapshotTableDesc = manifest.getTableDescriptor();
TableName tableName = TableName.valueOf(reqSnapshot.getTable());
@@ -697,9 +706,9 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
// Execute the restore/clone operation
if (MetaTableAccessor.tableExists(master.getConnection(), tableName)) {
if (master.getAssignmentManager().getTableStateManager().isTableState(
- TableName.valueOf(fsSnapshot.getTable()), ZooKeeperProtos.Table.State.ENABLED)) {
+ TableName.valueOf(snapshot.getTable()), ZooKeeperProtos.Table.State.ENABLED)) {
throw new UnsupportedOperationException("Table '" +
- TableName.valueOf(fsSnapshot.getTable()) + "' must be disabled in order to " +
+ TableName.valueOf(snapshot.getTable()) + "' must be disabled in order to " +
"perform a restore operation" +
".");
}
@@ -708,8 +717,8 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
if (cpHost != null) {
cpHost.preRestoreSnapshot(reqSnapshot, snapshotTableDesc);
}
- restoreSnapshot(fsSnapshot, snapshotTableDesc);
- LOG.info("Restore snapshot=" + fsSnapshot.getName() + " as table=" + tableName);
+ restoreSnapshot(snapshot, snapshotTableDesc);
+ LOG.info("Restore snapshot=" + snapshot.getName() + " as table=" + tableName);
if (cpHost != null) {
cpHost.postRestoreSnapshot(reqSnapshot, snapshotTableDesc);
@@ -719,8 +728,8 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
if (cpHost != null) {
cpHost.preCloneSnapshot(reqSnapshot, htd);
}
- cloneSnapshot(fsSnapshot, htd);
- LOG.info("Clone snapshot=" + fsSnapshot.getName() + " as table=" + tableName);
+ cloneSnapshot(snapshot, htd);
+ LOG.info("Clone snapshot=" + snapshot.getName() + " as table=" + tableName);
if (cpHost != null) {
cpHost.postCloneSnapshot(reqSnapshot, htd);
http://git-wip-us.apache.org/repos/asf/hbase/blob/926aaed1/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
index 91fcadc..6902aef 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/access/AccessController.java
@@ -98,6 +98,7 @@ import org.apache.hadoop.hbase.security.AccessDeniedException;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.UserProvider;
import org.apache.hadoop.hbase.security.access.Permission.Action;
+import org.apache.hadoop.hbase.snapshot.SnapshotDescriptionUtils;
import org.apache.hadoop.hbase.util.ByteRange;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
@@ -1234,7 +1235,8 @@ public class AccessController extends BaseMasterAndRegionObserver
public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
throws IOException {
- requirePermission("snapshot", Action.ADMIN);
+ requirePermission("snapshot", hTableDescriptor.getTableName(), null, null,
+ Permission.Action.ADMIN);
}
@Override
@@ -1248,13 +1250,22 @@ public class AccessController extends BaseMasterAndRegionObserver
public void preRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
throws IOException {
- requirePermission("restore", Action.ADMIN);
+ if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, getActiveUser())) {
+ requirePermission("restoreSnapshot", hTableDescriptor.getTableName(), null, null,
+ Permission.Action.ADMIN);
+ } else {
+ requirePermission("restore", Action.ADMIN);
+ }
}
@Override
public void preDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
final SnapshotDescription snapshot) throws IOException {
- requirePermission("deleteSnapshot", Action.ADMIN);
+ if (SnapshotDescriptionUtils.isSnapshotOwner(snapshot, getActiveUser())) {
+ // Snapshot owner is allowed to delete the snapshot
+ } else {
+ requirePermission("deleteSnapshot", Action.ADMIN);
+ }
}
@Override
http://git-wip-us.apache.org/repos/asf/hbase/blob/926aaed1/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java
index e1b1929..8888712 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/snapshot/SnapshotDescriptionUtils.java
@@ -29,7 +29,9 @@ import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.fs.permission.FsPermission;
import org.apache.hadoop.hbase.HConstants;
+import org.apache.hadoop.hbase.ipc.RequestContext;
import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
+import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.snapshot.SnapshotManifestV2;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
import org.apache.hadoop.hbase.util.FSUtils;
@@ -317,4 +319,16 @@ public class SnapshotDescriptionUtils {
}
}
+ /**
+ * Check if the user is this table snapshot's owner
+ * @param snapshot the table snapshot description
+ * @param user the user
+ * @return true if the user is the owner of the snapshot,
+ * false otherwise or the snapshot owner field is not present.
+ */
+ public static boolean isSnapshotOwner(final SnapshotDescription snapshot, final User user) {
+ if (user == null) return false;
+ if (!snapshot.hasOwner()) return false;
+ return snapshot.getOwner().equals(user.getShortName());
+ }
}
http://git-wip-us.apache.org/repos/asf/hbase/blob/926aaed1/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
index a07064b..0dea0a9 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/access/TestAccessController.java
@@ -94,6 +94,7 @@ import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.AccessControlService;
import org.apache.hadoop.hbase.protobuf.generated.AccessControlProtos.CheckPermissionsRequest;
+import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.regionserver.Region;
@@ -1799,11 +1800,17 @@ public class TestAccessController extends SecureTestUtil {
@Test
public void testSnapshot() throws Exception {
+ Admin admin = TEST_UTIL.getHBaseAdmin();
+ final HTableDescriptor htd = admin.getTableDescriptor(TEST_TABLE.getTableName());
+ SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
+ builder.setName(TEST_TABLE.getTableName().getNameAsString() + "-snapshot");
+ builder.setTable(TEST_TABLE.getTableName().getNameAsString());
+ final SnapshotDescription snapshot = builder.build();
AccessTestAction snapshotAction = new AccessTestAction() {
@Override
public Object run() throws Exception {
ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
- null, null);
+ snapshot, htd);
return null;
}
};
@@ -1812,7 +1819,7 @@ public class TestAccessController extends SecureTestUtil {
@Override
public Object run() throws Exception {
ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
- null);
+ snapshot);
return null;
}
};
@@ -1821,7 +1828,7 @@ public class TestAccessController extends SecureTestUtil {
@Override
public Object run() throws Exception {
ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
- null, null);
+ snapshot, htd);
return null;
}
};
@@ -1835,8 +1842,8 @@ public class TestAccessController extends SecureTestUtil {
}
};
- verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN);
- verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
+ verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER);
+ verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN);
verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
@@ -1849,6 +1856,62 @@ public class TestAccessController extends SecureTestUtil {
}
@Test
+ public void testSnapshotWithOwner() throws Exception {
+ Admin admin = TEST_UTIL.getHBaseAdmin();
+ final HTableDescriptor htd = admin.getTableDescriptor(TEST_TABLE.getTableName());
+ SnapshotDescription.Builder builder = SnapshotDescription.newBuilder();
+ builder.setName(TEST_TABLE.getTableName().getNameAsString() + "-snapshot");
+ builder.setTable(TEST_TABLE.getTableName().getNameAsString());
+ builder.setOwner(USER_OWNER.getName());
+ final SnapshotDescription snapshot = builder.build();
+ AccessTestAction snapshotAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ ACCESS_CONTROLLER.preSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
+ snapshot, htd);
+ return null;
+ }
+ };
+ verifyAllowed(snapshotAction, SUPERUSER, USER_ADMIN, USER_OWNER);
+ verifyDenied(snapshotAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
+
+ AccessTestAction deleteAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
+ snapshot);
+ return null;
+ }
+ };
+ verifyAllowed(deleteAction, SUPERUSER, USER_ADMIN, USER_OWNER);
+ verifyDenied(deleteAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
+
+ AccessTestAction restoreAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ ACCESS_CONTROLLER.preRestoreSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
+ snapshot, htd);
+ return null;
+ }
+ };
+ verifyAllowed(restoreAction, SUPERUSER, USER_ADMIN, USER_OWNER);
+ verifyDenied(restoreAction, USER_CREATE, USER_RW, USER_RO, USER_NONE);
+
+ AccessTestAction cloneAction = new AccessTestAction() {
+ @Override
+ public Object run() throws Exception {
+ ACCESS_CONTROLLER.preCloneSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
+ null, null);
+ return null;
+ }
+ };
+ // Clone by snapshot owner is not allowed , because clone operation creates a new table,
+ // which needs global admin permission.
+ verifyAllowed(cloneAction, SUPERUSER, USER_ADMIN);
+ verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
+ }
+
+ @Test
public void testGlobalAuthorizationForNewRegisteredRS() throws Exception {
LOG.debug("Test for global authorization for a new registered RegionServer.");
MiniHBaseCluster hbaseCluster = TEST_UTIL.getHBaseCluster();