HBASE-11869 Support snapshot owner
This commit is contained in:
parent
cf69a13f42
commit
c9e5229294
|
@ -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
|
||||
|
|
|
@ -164,6 +164,7 @@ message SnapshotDescription {
|
|||
}
|
||||
optional Type type = 4 [default = FLUSH];
|
||||
optional int32 version = 5;
|
||||
optional string owner = 6;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,6 +45,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;
|
||||
|
@ -63,6 +64,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;
|
||||
|
@ -257,6 +259,18 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
* @throws IOException For filesystem IOExceptions
|
||||
*/
|
||||
public void deleteSnapshot(SnapshotDescription snapshot) throws SnapshotDoesNotExistException, IOException {
|
||||
// check to see if it is completed
|
||||
if (!isSnapshotCompleted(snapshot)) {
|
||||
throw new SnapshotDoesNotExistException(snapshot);
|
||||
}
|
||||
|
||||
String snapshotName = snapshot.getName();
|
||||
// first create the snapshot description and check to see if it exists
|
||||
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();
|
||||
|
@ -264,19 +278,9 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
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();
|
||||
Path snapshotDir = SnapshotDescriptionUtils.getCompletedSnapshotDir(snapshotName, rootDir);
|
||||
|
||||
// delete the existing snapshot
|
||||
if (!fs.getFileSystem().delete(snapshotDir, true)) {
|
||||
if (!fs.delete(snapshotDir, true)) {
|
||||
throw new HBaseSnapshotException("Failed to delete snapshot directory: " + snapshotDir);
|
||||
}
|
||||
|
||||
|
@ -540,13 +544,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();
|
||||
|
@ -680,10 +687,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());
|
||||
|
||||
|
@ -696,9 +705,9 @@ public class SnapshotManager extends MasterProcedureManager implements Stoppable
|
|||
// Execute the restore/clone operation
|
||||
if (MetaTableAccessor.tableExists(master.getShortCircuitConnection(), 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" +
|
||||
".");
|
||||
}
|
||||
|
@ -707,8 +716,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);
|
||||
|
@ -718,8 +727,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);
|
||||
|
|
|
@ -94,6 +94,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;
|
||||
|
@ -1055,7 +1056,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
|
||||
|
@ -1069,13 +1071,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
|
||||
|
|
|
@ -29,8 +29,10 @@ 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;
|
||||
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;
|
||||
|
@ -318,4 +320,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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,6 +88,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.RegionCoprocessorHost;
|
||||
|
@ -1824,11 +1825,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;
|
||||
}
|
||||
};
|
||||
|
@ -1837,7 +1844,7 @@ public class TestAccessController extends SecureTestUtil {
|
|||
@Override
|
||||
public Object run() throws Exception {
|
||||
ACCESS_CONTROLLER.preDeleteSnapshot(ObserverContext.createAndPrepare(CP_ENV, null),
|
||||
null);
|
||||
snapshot);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
@ -1846,7 +1853,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;
|
||||
}
|
||||
};
|
||||
|
@ -1860,8 +1867,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);
|
||||
|
@ -1873,6 +1880,62 @@ public class TestAccessController extends SecureTestUtil {
|
|||
verifyDenied(cloneAction, USER_CREATE, USER_RW, USER_RO, USER_NONE, USER_OWNER);
|
||||
}
|
||||
|
||||
@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.");
|
||||
|
|
Loading…
Reference in New Issue