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();