Repository: sentry
Updated Branches:
  refs/heads/master b00285486 -> 94cfb1b42


SENTRY-2115: Incorrect behavior of HMsFollower when HDFSSync feature is 
disabled.(Kalyan Kumar kalvagadda, reviewed-by Na Li, Sergio Pena and Xinran 
Tinney)


Project: http://git-wip-us.apache.org/repos/asf/sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/sentry/commit/94cfb1b4
Tree: http://git-wip-us.apache.org/repos/asf/sentry/tree/94cfb1b4
Diff: http://git-wip-us.apache.org/repos/asf/sentry/diff/94cfb1b4

Branch: refs/heads/master
Commit: 94cfb1b425b64285385fcb716a1c12877c24d6d0
Parents: b002854
Author: Kalyan Kumar Kalvagadda <kkal...@cloudera.com>
Authored: Thu Feb 22 07:38:19 2018 -0600
Committer: Kalyan Kumar Kalvagadda <kkal...@cloudera.com>
Committed: Thu Feb 22 07:38:19 2018 -0600

----------------------------------------------------------------------
 .../apache/sentry/hdfs/DBUpdateForwarder.java   |   1 +
 .../org/apache/sentry/hdfs/SentryPlugin.java    |   4 +-
 .../db/service/persistent/HMSFollower.java      |  67 +++-
 .../persistent/NotificationProcessor.java       |   2 +-
 .../db/service/persistent/SentryStore.java      |  25 +-
 .../sentry/service/thrift/SentryService.java    |  11 +
 .../db/service/persistent/TestHMSFollower.java  | 308 ++++++++++++++++---
 .../tests/e2e/hdfs/TestHDFSIntegrationBase.java |   2 +-
 .../hdfs/TestHDFSIntegrationTogglingConf.java   | 211 +++++++++++++
 .../tests/e2e/minisentry/InternalSentrySrv.java |  11 +
 .../sentry/tests/e2e/minisentry/SentrySrv.java  |  10 +
 11 files changed, 591 insertions(+), 61 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/DBUpdateForwarder.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/DBUpdateForwarder.java
 
b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/DBUpdateForwarder.java
index eae7861..71ef5f9 100644
--- 
a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/DBUpdateForwarder.java
+++ 
b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/DBUpdateForwarder.java
@@ -108,6 +108,7 @@ class DBUpdateForwarder<K extends Updateable.Update> {
 
     if (seqNum > curSeqNum) {
       // No new notifications were processed.
+      LOGGER.debug("{}, No new updates", retrieverType);
       return Collections.emptyList();
     }
 

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
----------------------------------------------------------------------
diff --git 
a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
 
b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
index cf764ed..8485ca3 100644
--- 
a/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
+++ 
b/sentry-hdfs/sentry-hdfs-service/src/main/java/org/apache/sentry/hdfs/SentryPlugin.java
@@ -158,7 +158,7 @@ public class SentryPlugin implements 
SentryPolicyStorePlugin, SigUtils.SigListen
   public List<PathsUpdate> getAllPathsUpdatesFrom(long pathSeqNum, long 
pathImgNum) throws Exception {
     if (!fullUpdateNN.get()) {
       // Most common case - Sentry is NOT handling a full update.
-      LOGGER.debug("Sending partial PATH update to NameNode for pathSeqNum {} 
and pathImgNum {}", pathSeqNum, pathImgNum);
+      LOGGER.debug("Received request for PATH update from NameNode for 
pathSeqNum {} and pathImgNum {}", pathSeqNum, pathImgNum);
       return pathsUpdater.getAllUpdatesFrom(pathSeqNum, pathImgNum);
     }
 
@@ -199,7 +199,7 @@ public class SentryPlugin implements 
SentryPolicyStorePlugin, SigUtils.SigListen
   }
 
   public List<PermissionsUpdate> getAllPermsUpdatesFrom(long permSeqNum) 
throws Exception {
-    LOGGER.debug("Sending partial PERM update to NameNode for permSeqNum {}", 
permSeqNum);
+    LOGGER.debug("Received request for PERM update from NameNode for 
permSeqNum {}", permSeqNum);
     return permsUpdater.getAllUpdatesFrom(permSeqNum, 
UNUSED_PATH_UPDATE_IMG_NUM);
   }
 

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HMSFollower.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HMSFollower.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HMSFollower.java
index 2f2b984..929e6be 100644
--- 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HMSFollower.java
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/HMSFollower.java
@@ -116,7 +116,17 @@ public class HMSFollower implements Runnable, 
AutoCloseable, PubSub.Subscriber {
       LOGGER.info(FULL_UPDATE_TRIGGER + "subscribing to topic " + 
PubSub.Topic.HDFS_SYNC_HMS.getName());
       PubSub.getInstance().subscribe(PubSub.Topic.HDFS_SYNC_HMS, this);
     }
-
+    if(!hdfsSyncEnabled) {
+      try {
+        // Clear all the HMS metadata learned so far and learn it fresh when 
the feature
+        // is enabled back.
+        store.clearHmsPathInformation();
+      } catch (Exception ex) {
+        LOGGER.error("Failed to clear HMS path info", ex);
+        LOGGER.error("Please manually clear data from 
SENTRY_PATH_CHANGE/AUTHZ_PATH/AUTHZ_PATHS_MAPPING tables." +
+                "If not, HDFS ACL's will be inconsistent when HDFS sync 
feature is enabled back.");
+      }
+    }
   }
 
   @VisibleForTesting
@@ -190,7 +200,7 @@ public class HMSFollower implements Runnable, 
AutoCloseable, PubSub.Subscriber {
    * <p>Clients connections waiting for an event notification will be
    * woken up afterwards.
    */
-  private void syncupWithHms(long notificationId) {
+   void syncupWithHms(long notificationId) {
     try {
       client.connect();
       connectedToHms = true;
@@ -201,18 +211,27 @@ public class HMSFollower implements Runnable, 
AutoCloseable, PubSub.Subscriber {
     }
 
     try {
-      /* Before getting notifications, it checks if a full HMS snapshot is 
required. */
-      if (isFullSnapshotRequired(notificationId)) {
-        createFullSnapshot();
-        return;
+      if (hdfsSyncEnabled) {
+        // Before getting notifications, checking if a full HMS snapshot is 
required.
+        if (isFullSnapshotRequired(notificationId)) {
+          createFullSnapshot();
+          return;
+        }
+      } else if (isSentryOutOfSync(notificationId)) {
+        // Out-of-sync, fetching all the notifications
+        // in HMS NOTIFICATION_LOG.
+        sentryStore.setLastProcessedNotificationID(0L);
+        notificationId = 0L;
       }
 
       Collection<NotificationEvent> notifications =
           notificationFetcher.fetchNotifications(notificationId);
 
-      // After getting notifications, it checks if the HMS did some clean-up 
and notifications
+      // After getting notifications, check if HMS did some clean-up and 
notifications
       // are out-of-sync with Sentry.
-      if (areNotificationsOutOfSync(notifications, notificationId)) {
+      if (hdfsSyncEnabled &&
+              areNotificationsOutOfSync(notifications, notificationId)) {
+        // Out-of-sync, taking a HMS full snapshot.
         createFullSnapshot();
         return;
       }
@@ -258,18 +277,15 @@ public class HMSFollower implements Runnable, 
AutoCloseable, PubSub.Subscriber {
       return true;
     }
 
-    // Once HDFS sync is enabled, and if MAuthzPathsSnapshotId
+    // Once HDFS sync is enabled, and if MAuthzPathsMapping
     // table is still empty, we need to request a full snapshot
-    if(hdfsSyncEnabled && sentryStore.isAuthzPathsSnapshotEmpty()) {
-      LOGGER.debug("HDFSSync is enabled and MAuthzPathsSnapshotId table is 
empty. Need to request a full snapshot");
+    if (sentryStore.isAuthzPathsSnapshotEmpty()) {
+      LOGGER.debug("HDFSSync is enabled and MAuthzPathsMapping table is 
empty." +
+              " Need to request a full snapshot");
       return true;
     }
 
-    long currentHmsNotificationId = 
notificationFetcher.getCurrentNotificationId();
-    if (currentHmsNotificationId < latestSentryNotificationId) {
-      LOGGER.info("The current notification ID on HMS = {} is less than the 
latest processed Sentry "
-          + "notification ID = {}. Need to request a full HMS snapshot",
-          currentHmsNotificationId, latestSentryNotificationId);
+    if(isSentryOutOfSync(latestSentryNotificationId)) {
       return true;
     }
 
@@ -284,6 +300,25 @@ public class HMSFollower implements Runnable, 
AutoCloseable, PubSub.Subscriber {
   }
 
   /**
+   * Checks the last notification processed by sentry and the current event-id 
of
+   * HMS to see if sentry is out of sync.
+   *
+   * @param latestSentryNotificationId The notification Id to check against 
the HMS
+   * @return True, sentry is out-of-sync, False otherwise
+   * @throws Exception If an error occurs while fetching the current 
notification from HMS
+   */
+  private boolean isSentryOutOfSync(long latestSentryNotificationId) throws 
Exception {
+    long currentHmsNotificationId = 
notificationFetcher.getCurrentNotificationId();
+    if (currentHmsNotificationId < latestSentryNotificationId) {
+      LOGGER.info("The current notification ID on HMS = {} is less than the 
latest processed Sentry "
+                      + "notification ID = {}. Sentry, Out-of-sync",
+              currentHmsNotificationId, latestSentryNotificationId);
+      return true;
+    }
+    return false;
+  }
+
+  /**
    * Checks if the HMS and Sentry processed notifications are out-of-sync.
    * This could happen because the HMS did some clean-up of old notifications
    * and Sentry was not requesting notifications during that time.

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/NotificationProcessor.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/NotificationProcessor.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/NotificationProcessor.java
index e755837..94a0b0f 100644
--- 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/NotificationProcessor.java
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/NotificationProcessor.java
@@ -99,7 +99,7 @@ final class NotificationProcessor {
             AUTHZ_SYNC_CREATE_WITH_POLICY_STORE.getDefault()));
     syncStoreOnDrop = 
Boolean.parseBoolean(conf.get(AUTHZ_SYNC_DROP_WITH_POLICY_STORE.getVar(),
         AUTHZ_SYNC_DROP_WITH_POLICY_STORE.getDefault()));
-    hdfsSyncEnabled = SentryServiceUtil.isHDFSSyncEnabled(conf);
+    hdfsSyncEnabled = SentryServiceUtil.isHDFSSyncEnabledNoCache(conf);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
index edea5b6..7a31a01 100644
--- 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/SentryStore.java
@@ -577,6 +577,25 @@ public class SentryStore {
   }
 
   /**
+   * Removes all the information related to HMS Objects from sentry store.
+   */
+  @VisibleForTesting
+  public void clearHmsPathInformation() throws Exception {
+    tm.executeTransactionWithRetry(
+            new TransactionBlock<Object>() {
+              public Object execute(PersistenceManager pm) throws Exception {
+                // Data in MAuthzPathsSnapshotId.class is not cleared 
intentionally.
+                // This data will help sentry retain the history of snapshots 
taken before
+                // and help in picking appropriate ID even when hdfs sync is 
enabled/disabled.
+                pm.newQuery(MSentryPathChange.class).deletePersistentAll();
+                pm.newQuery(MAuthzPathsMapping.class).deletePersistentAll();
+                pm.newQuery(MPath.class).deletePersistentAll();
+                return null;
+              }
+            });
+  }
+
+  /**
    * Purge a given delta change table, with a specified number of changes to 
be kept.
    *
    * @param cls the class of a perm/path delta change {@link 
MSentryPermChange} or
@@ -3101,9 +3120,9 @@ public class SentryStore {
   }
 
   /**
-   * Tells if there are any records in MAuthzPathsSnapshotId
+   * Tells if there are any records in MAuthzPathsMapping
    *
-   * @return true if there are no entries in <code>MAuthzPathsSnapshotId</code>
+   * @return true if there are no entries in <code>MAuthzPathsMapping</code>
    * false if there are entries
    * @throws Exception
    */
@@ -3112,7 +3131,7 @@ public class SentryStore {
         new TransactionBlock<Boolean>() {
           public Boolean execute(PersistenceManager pm) throws Exception {
             pm.setDetachAllOnCommit(false); // No need to detach objects
-            return isTableEmptyCore(pm, MAuthzPathsSnapshotId.class);
+            return isTableEmptyCore(pm, MAuthzPathsMapping.class);
           }
         });
   }

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
index 96c6810..bf5d85b 100644
--- 
a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
+++ 
b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/SentryService.java
@@ -642,4 +642,15 @@ public class SentryService implements Callable, 
SigUtils.SigListener {
     // Become follower
     leaderMonitor.deactivate();
   }
+
+  /**
+   * Restart HMSFollower with new configuration
+   * @param newConf Configuration
+   * @throws Exception
+   */
+  @VisibleForTesting
+  public void restartHMSFollower(Configuration newConf) throws Exception{
+    stopHMSFollower(conf);
+    startHMSFollower(newConf);
+  }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestHMSFollower.java
----------------------------------------------------------------------
diff --git 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestHMSFollower.java
 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestHMSFollower.java
index 7903078..61e3f06 100644
--- 
a/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestHMSFollower.java
+++ 
b/sentry-provider/sentry-provider-db/src/test/java/org/apache/sentry/provider/db/service/persistent/TestHMSFollower.java
@@ -60,6 +60,7 @@ import 
org.apache.sentry.provider.db.service.thrift.TSentryAuthorizable;
 import static 
org.apache.sentry.hdfs.ServiceConstants.ServerConfig.SENTRY_SERVICE_FULL_UPDATE_PUBSUB;
 
 import org.junit.Before;
+import org.junit.After;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -87,17 +88,34 @@ public class TestHMSFollower {
     configuration.set("sentry.hive.sync.create", "true");
     configuration.set(SENTRY_SERVICE_FULL_UPDATE_PUBSUB, "true");
 
-    // enable HDFS sync, so perm and path changes will be saved into DB
-    configuration.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES, 
"org.apache.sentry.hdfs.SentryHDFSServiceProcessorFactory");
-    
configuration.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS, 
"org.apache.sentry.hdfs.SentryPlugin");
+    enableHdfsSyncInSentry(configuration);
   }
 
   @Before
   public void setupMocks() throws Exception {
-    reset(hmsConnectionMock, hmsClientMock);
+    reset(hmsConnectionMock, hmsClientMock, sentryStore);
     when(hmsConnectionMock.connect()).thenReturn(new HMSClient(hmsClientMock));
   }
 
+  @After
+  public void resetConfig() throws Exception {
+    enableHdfsSyncInSentry(configuration);
+  }
+
+  private static void enableHdfsSyncInSentry(Configuration conf) {
+    // enable HDFS sync, so perm and path changes will be saved into DB
+    conf.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES,
+            "org.apache.sentry.hdfs.SentryHDFSServiceProcessorFactory");
+    conf.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS,
+            "org.apache.sentry.hdfs.SentryPlugin");
+  }
+
+  private static void disableHdfsSyncInSentry(Configuration conf) {
+    // enable HDFS sync, so perm and path changes will be saved into DB
+    conf.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES, "");
+    conf.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS, "");
+  }
+
   @Test
   public void testPersistAFullSnapshotWhenNoSnapshotAreProcessedYet() throws 
Exception {
     /*
@@ -252,19 +270,17 @@ public class TestHMSFollower {
      *
      * HMS client always returns the paths image with the eventId == 1.
      *
-     * On the 1st run:  Sentry notification table is empty, so this
-     * should trigger a new full HMS snapshot request with the eventId = 1
-     * but it should not persist it, in stead only set last
-     * last processed notification Id. This will prevent a
-     * unless until notifications are out of sync or hdfs sync is enabled
+     * On the 1st run:   Hdfs sync is disabled in sentry server
+     * Sentry notification table is empty, so this
+     * should not trigger a new full HMS snapshot request but should
+     * fetch all the HMS notifications and persist them.
      *
      * On the 2nd run: Just enable hdfs sync and a full snapshot should be 
triggered
-     * because MAuthzPathsSnapshotId table is empty
+     * because MAuthzPathsMapping table is empty
      *
      */
 
-    configuration.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES, "");
-    
configuration.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS, 
"");
+    disableHdfsSyncInSentry(configuration);
 
     final long SENTRY_PROCESSED_EVENT_ID = SentryStore.EMPTY_NOTIFICATION_ID;
     final long HMS_PROCESSED_EVENT_ID = 1L;
@@ -287,19 +303,20 @@ public class TestHMSFollower {
     
when(sentryStore.getLastProcessedNotificationID()).thenReturn(SENTRY_PROCESSED_EVENT_ID);
     when(sentryStore.isHmsNotificationEmpty()).thenReturn(true);
     hmsFollower.run();
+    // Since HDFS sync is disabled, fullsnapshot should not be fetched from HMS
     verify(sentryStore, times(0)).persistFullPathsImage(
         fullSnapshot.getPathImage(), fullSnapshot.getId());
-    // Since hdfs sync is disabled we would set last processed notifications
-    // and since we did trigger createFullSnapshot() method we won't process 
any notifications
-    verify(sentryStore, 
times(1)).setLastProcessedNotificationID(fullSnapshot.getId());
-    verify(sentryStore, 
times(0)).persistLastProcessedNotificationID(fullSnapshot.getId());
+    verify(sentryStore, times(1)).getLastProcessedNotificationID();
+    // Making sure that HMS client is invoked to get all the notifications
+    // starting from event-id 0
+    verify(hmsClientMock, times(1)).getNextNotification(Mockito.eq(0L),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
 
     reset(sentryStore);
 
     //Re-enable HDFS Sync and simply start the HMS follower thread, full snap 
shot
-    // should be triggered because MAuthzPathsSnapshotId table is empty
-    configuration.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES, 
"org.apache.sentry.hdfs.SentryHDFSServiceProcessorFactory");
-    
configuration.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS, 
"org.apache.sentry.hdfs.SentryPlugin");
+    // should be triggered because MAuthzPathsMapping table is empty
+    enableHdfsSyncInSentry(configuration);
 
     //Create a new hmsFollower instance since configuration is changing
     hmsFollower = new HMSFollower(configuration, sentryStore, null,
@@ -333,7 +350,141 @@ public class TestHMSFollower {
     verify(sentryStore, 
times(0)).setLastProcessedNotificationID(fullSnapshot.getId());
     verify(sentryStore, 
times(0)).persistLastProcessedNotificationID(fullSnapshot.getId());
 
-    reset(sentryStore);
+  }
+
+  @Test
+  public void testDisablingAndEnablingHDFSSync() throws Exception {
+    /*
+     * TEST CASE
+     *
+     * Simulates (by using mocks) the following:
+     *
+     * Disable HDFSSync before and enable it later.
+     *
+     * HMS client always returns the paths image with the eventId == 1.
+     *
+     * On the 1st run:  Hdfs sync is disabled in sentry server.
+     * This should not trigger a new full HMS snapshot request but should
+     * fetch all the HMS notifications and persist them.
+     *
+     * On the 2nd run: Hdfs sync is enabled in sentry server
+      * Full snapshot should be fetched and persisted because 
MAuthzPathsMapping table is empty
+     *
+     * On 3rd run: Hdfs sync is disabled in sentry server.
+     * Sentry should remove the HMS path information(MAuthzPathsMapping and 
MSentryPathChange)
+     * but continue to process the notifications based on the information 
persisted in MSentryHmsNotification.
+     *
+     * on 4th run: Hdfs sync is enabled in sentry server
+     * Full snapshot should be fetched and persisted because 
MAuthzPathsMapping table is empty
+     *
+     */
+
+    disableHdfsSyncInSentry(configuration);
+
+    final long SENTRY_PROCESSED_EVENT_ID = SentryStore.EMPTY_NOTIFICATION_ID;
+    final long HMS_PROCESSED_EVENT_ID = 1L;
+
+    // Mock that returns a full snapshot
+    Map<String, Collection<String>> snapshotObjects = new HashMap<>();
+    snapshotObjects.put("db", Sets.newHashSet("/db"));
+    snapshotObjects.put("db.table", Sets.newHashSet("/db/table"));
+    PathsImage fullSnapshot = new PathsImage(snapshotObjects, 
HMS_PROCESSED_EVENT_ID, 1);
+
+    SentryHMSClient sentryHmsClient = Mockito.mock(SentryHMSClient.class);
+    when(sentryHmsClient.getFullSnapshot()).thenReturn(fullSnapshot);
+
+    NotificationEventResponse response = new NotificationEventResponse();
+
+    response.addToEvents(new NotificationEvent(1L, 0, "CREATE_DATABASE", ""));
+    response.addToEvents(new NotificationEvent(2L, 0, "CREATE_TABLE", ""));
+    response.addToEvents(new NotificationEvent(3L, 0, "ALTER_TABLE", ""));
+
+    when(hmsClientMock.getNextNotification(Mockito.eq(0L), 
Mockito.eq(Integer.MAX_VALUE),
+            Mockito.anyObject())).thenReturn(response);
+
+    HMSFollower hmsFollower = new HMSFollower(configuration, sentryStore, null,
+            hmsConnectionMock, hiveInstance);
+    hmsFollower.setSentryHmsClient(sentryHmsClient);
+
+    // 1st run should not fetch full snapshot but should fetch notifications 
from 0
+    // and persists them
+    
when(sentryStore.getLastProcessedNotificationID()).thenReturn(SENTRY_PROCESSED_EVENT_ID);
+    when(sentryStore.isHmsNotificationEmpty()).thenReturn(true);
+    hmsFollower.run();
+    verify(sentryStore, times(0)).persistFullPathsImage(
+            fullSnapshot.getPathImage(), fullSnapshot.getId());
+    verify(sentryStore, times(1)).clearHmsPathInformation();
+    // Making sure that HMS client is invoked to get all the notifications
+    // starting from event-id 0
+    verify(hmsClientMock, times(1)).getNextNotification(Mockito.eq(0L),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
+    verify(sentryStore, times(1)).persistLastProcessedNotificationID(1L);
+    verify(sentryStore, times(1)).persistLastProcessedNotificationID(2L);
+    verify(sentryStore, times(1)).persistLastProcessedNotificationID(3L);
+
+    reset(sentryStore, hmsClientMock);
+
+    //Enable HDFS sync to make sure that Full snapshot is fetched from HMS and 
persisted.
+    enableHdfsSyncInSentry(configuration);
+    when(sentryStore.isHmsNotificationEmpty()).thenReturn(false);
+    
when(sentryStore.getLastProcessedNotificationID()).thenReturn(HMS_PROCESSED_EVENT_ID);
+    when(sentryStore.isAuthzPathsSnapshotEmpty()).thenReturn(true);
+    // Mock that sets the current HMS notification ID. Set it to match
+    // last processed notification Id so that doesn't trigger a full snapshot
+    when(hmsClientMock.getCurrentNotificationEventId())
+            .thenReturn(new 
CurrentNotificationEventId(HMS_PROCESSED_EVENT_ID));
+    hmsFollower = new HMSFollower(configuration, sentryStore, null,
+            hmsConnectionMock, hiveInstance);
+    hmsFollower.setSentryHmsClient(sentryHmsClient);
+
+    // 2nd run get a full snapshot because there was no snapshot persisted 
before.
+    hmsFollower.run();
+    verify(sentryStore, times(0)).clearHmsPathInformation();
+    verify(sentryStore, times(1)).persistFullPathsImage(
+            fullSnapshot.getPathImage(), fullSnapshot.getId());
+    verify(sentryStore, 
times(0)).setLastProcessedNotificationID(fullSnapshot.getId());
+
+    reset(sentryStore, hmsClientMock);
+
+    disableHdfsSyncInSentry(configuration);
+    when(sentryStore.isHmsNotificationEmpty()).thenReturn(false);
+    
when(sentryStore.getLastProcessedNotificationID()).thenReturn(HMS_PROCESSED_EVENT_ID);
+    when(sentryStore.isAuthzPathsSnapshotEmpty()).thenReturn(true);
+    // Mock that sets the current HMS notification ID. Set it to match
+    // last processed notification Id so that doesn't trigger a full snapshot
+    when(hmsClientMock.getCurrentNotificationEventId())
+            .thenReturn(new 
CurrentNotificationEventId(HMS_PROCESSED_EVENT_ID));
+
+    hmsFollower = new HMSFollower(configuration, sentryStore, null,
+            hmsConnectionMock, hiveInstance);
+    hmsFollower.setSentryHmsClient(sentryHmsClient);
+    // 3rd run
+    hmsFollower.run();
+    verify(sentryStore, times(0)).persistFullPathsImage(
+            fullSnapshot.getPathImage(), fullSnapshot.getId());
+    verify(sentryStore, times(1)).clearHmsPathInformation();
+    verify(sentryStore, 
times(0)).setLastProcessedNotificationID(Mockito.anyLong());
+    //Make sure that HMSFollower continues to fetch notifications based on 
persisted notifications.
+    verify(hmsClientMock, 
times(1)).getNextNotification(Mockito.eq(fullSnapshot.getId()-1),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
+
+    reset(sentryStore, hmsClientMock);
+    enableHdfsSyncInSentry(configuration);
+    when(sentryStore.isHmsNotificationEmpty()).thenReturn(false);
+    
when(sentryStore.getLastProcessedNotificationID()).thenReturn(HMS_PROCESSED_EVENT_ID);
+    when(sentryStore.isAuthzPathsSnapshotEmpty()).thenReturn(true);
+
+    hmsFollower = new HMSFollower(configuration, sentryStore, null,
+            hmsConnectionMock, hiveInstance);
+    hmsFollower.setSentryHmsClient(sentryHmsClient);
+    // 4th run
+    hmsFollower.run();
+    verify(sentryStore, times(0)).clearHmsPathInformation();
+    verify(sentryStore, times(1)).persistFullPathsImage(
+            fullSnapshot.getPathImage(), fullSnapshot.getId());
+    verify(sentryStore, 
times(0)).setLastProcessedNotificationID(fullSnapshot.getId());
+
+    reset(sentryStore, hmsClientMock);
   }
 
   @Test
@@ -843,8 +994,7 @@ public class TestHMSFollower {
 
     Configuration configuration = new Configuration();
     // enable HDFS sync, so perm and path changes will be saved into DB
-    configuration.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES, 
"org.apache.sentry.hdfs.SentryHDFSServiceProcessorFactory");
-    
configuration.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS, 
"org.apache.sentry.hdfs.SentryPlugin");
+    enableHdfsSyncInSentry(configuration);
 
     HMSFollower hmsFollower = new HMSFollower(configuration, sentryStore, null,
         hiveConnectionFactory, hiveInstance);
@@ -968,6 +1118,7 @@ public class TestHMSFollower {
     events.add(notificationEvent);
 
     Configuration configuration = new Configuration();
+    enableHdfsSyncInSentry(configuration);
     HMSFollower hmsFollower = new HMSFollower(configuration, sentryStore, null,
         hiveConnectionFactory, hiveInstance);
     hmsFollower.processNotifications(events);
@@ -983,28 +1134,32 @@ public class TestHMSFollower {
 
   @Test
   public void testNoHdfsNoPersistAFullSnapshot() throws Exception {
-    /*
-     * TEST CASE
-     *
-     * Simulates (by using mocks) that Sentry has not processed any 
notifications, so this
-     * should trigger a new full HMS snapshot request with the eventId = 1
-     */
+
+     // TEST CASE
+     //
+     // Simulates (by using mocks) that Sentry has not processed any 
notifications.
+     // Test makes sure that this does not trigger a full snapshot and also 
makes sure that
+     // HMSFollower tries to fetch all notifications from HMS.
+
 
     final long SENTRY_PROCESSED_EVENT_ID = SentryStore.EMPTY_NOTIFICATION_ID;
     final long HMS_PROCESSED_EVENT_ID = 1L;
 
-    // Mock that returns a full snapshot
-    Map<String, Collection<String>> snapshotObjects = new HashMap<>();
-    snapshotObjects.put("db", Sets.newHashSet("/db"));
-    snapshotObjects.put("db.table", Sets.newHashSet("/db/table"));
-    PathsImage fullSnapshot = new PathsImage(snapshotObjects, 
HMS_PROCESSED_EVENT_ID, 1);
+    NotificationEventResponse response = new NotificationEventResponse();
+
+    response.addToEvents(new NotificationEvent(1L, 0, "CREATE_DATABASE", ""));
+    response.addToEvents(new NotificationEvent(1L, 0, "CREATE_TABLE", ""));
+    response.addToEvents(new NotificationEvent(2L, 0, "ALTER_TABLE", ""));
 
     // Mock that returns the current HMS notification ID
     when(hmsClientMock.getCurrentNotificationEventId())
-        .thenReturn(new CurrentNotificationEventId(fullSnapshot.getId()));
+        .thenReturn(new CurrentNotificationEventId(HMS_PROCESSED_EVENT_ID));
+
+    when(hmsClientMock.getNextNotification(Mockito.eq(0L), 
Mockito.eq(Integer.MAX_VALUE),
+            Mockito.anyObject())).thenReturn(response);
 
     SentryHMSClient sentryHmsClient = Mockito.mock(SentryHMSClient.class);
-    when(sentryHmsClient.getFullSnapshot()).thenReturn(fullSnapshot);
+   // when(sentryHmsClient.getFullSnapshot()).thenReturn(fullSnapshot);
 
     Configuration configuration = new Configuration();
     HMSFollower hmsFollower = new HMSFollower(configuration, sentryStore, null,
@@ -1016,10 +1171,87 @@ public class TestHMSFollower {
     when(sentryStore.isAuthzPathsMappingEmpty()).thenReturn(false);
     when(sentryStore.isHmsNotificationEmpty()).thenReturn(true);
     hmsFollower.run();
-    verify(sentryStore, 
times(0)).persistFullPathsImage(fullSnapshot.getPathImage(), 
fullSnapshot.getId());
-    verify(sentryStore, 
times(1)).setLastProcessedNotificationID(fullSnapshot.getId());
-    verify(sentryStore, times(1)).isHmsNotificationEmpty();
+    verify(sentryStore, times(0)).persistFullPathsImage(Mockito.anyMap(), 
Mockito.anyLong());
     verify(sentryStore, times(0)).isAuthzPathsMappingEmpty();
+    verify(hmsClientMock, times(1)).getNextNotification(Mockito.eq(0L),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
+    verify(sentryStore, 
times(3)).persistLastProcessedNotificationID(Mockito.anyLong());
+  }
+
+  /**
+   * Tests the out-of-sync scenario when HDFS sync is disabled to make sure 
that
+   * HMSFollower starting fetching notifications from beginning after 
out-of-sync
+   * is detected.
+   * @throws Exception
+   */
+  @Test
+  public void testNoHdfsOutofSync() throws Exception {
+
+    // TEST CASE
+    //
+    // Simulates (by using mocks) that Sentry is out-of-sync with sentry
+
+    final long SENTRY_PROCESSED_EVENT_ID = SentryStore.EMPTY_NOTIFICATION_ID;
+
+    NotificationEventResponse response = new NotificationEventResponse();
+
+    response.addToEvents(new NotificationEvent(1L, 0, "CREATE_DATABASE", ""));
+    response.addToEvents(new NotificationEvent(2L, 0, "CREATE_TABLE", ""));
+    response.addToEvents(new NotificationEvent(3L, 0, "ALTER_TABLE", ""));
+
+    // Mock that returns the current HMS notification ID
+    when(hmsClientMock.getCurrentNotificationEventId())
+            .thenReturn(new CurrentNotificationEventId(3L));
+
+    when(hmsClientMock.getNextNotification(Mockito.eq(0L), 
Mockito.eq(Integer.MAX_VALUE),
+            Mockito.anyObject())).thenReturn(response);
+
+    SentryHMSClient sentryHmsClient = Mockito.mock(SentryHMSClient.class);
+
+    Configuration configuration = new Configuration();
+    HMSFollower hmsFollower = new HMSFollower(configuration, sentryStore, null,
+            hmsConnectionMock, hiveInstance);
+    hmsFollower.setSentryHmsClient(sentryHmsClient);
+
+    // 1st run should not fetch t he full snapshot but should fetch all the 
notifications
+    // from HMS.
+    
when(sentryStore.getLastProcessedNotificationID()).thenReturn(SENTRY_PROCESSED_EVENT_ID);
+    when(sentryStore.isAuthzPathsMappingEmpty()).thenReturn(false);
+    when(sentryStore.isHmsNotificationEmpty()).thenReturn(true);
+    hmsFollower.run();
+    verify(sentryStore, times(0)).persistFullPathsImage(Mockito.anyMap(), 
Mockito.anyLong());
+    verify(sentryStore, times(0)).isAuthzPathsMappingEmpty();
+    verify(hmsClientMock, times(1)).getNextNotification(Mockito.eq(0L),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
+    verify(sentryStore, 
times(3)).persistLastProcessedNotificationID(Mockito.anyLong());
+    reset(sentryStore, hmsClientMock);
+
+    //Update the mock so that it returns the max(event-id) that was fetched in 
previous run
+    when(sentryStore.getLastProcessedNotificationID()).thenReturn(3L);
+    // Mock HMSClient so that it returns appropriate event-id
+    when(hmsClientMock.getCurrentNotificationEventId())
+            .thenReturn(new CurrentNotificationEventId(3L));
+
+    //2nd run
+    hmsFollower.run();
+    // Verify that HMSFollower starting fetching the notifications beyond what 
it already processed.
+    verify(hmsClientMock, times(1)).getNextNotification(Mockito.eq(3L-1),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
+
+
+    // Mock that returns the current HMS notification ID which is less than 
what
+    // sentry already processed.
+    when(hmsClientMock.getCurrentNotificationEventId())
+            .thenReturn(new CurrentNotificationEventId(1L));
+    //Update the mock so that it returns the max(event-id) that was fetched in 
previous run
+    when(sentryStore.getLastProcessedNotificationID()).thenReturn(0L);
+
+    // 3rd run
+    hmsFollower.syncupWithHms(3L);
+    verify(hmsClientMock, times(1)).getNextNotification(Mockito.eq(0L),
+            Mockito.eq(Integer.MAX_VALUE), Mockito.anyObject());
+
+
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
----------------------------------------------------------------------
diff --git 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
index 4cd00e6..9b0aeb2 100644
--- 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
+++ 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationBase.java
@@ -204,6 +204,7 @@ public abstract class TestHDFSIntegrationBase {
   protected static Boolean hiveSyncOnDrop = true;
   protected static Configuration hadoopConf;
   protected static final Map<String, String> sentryProperties = 
Maps.newHashMap();
+  protected static Configuration sentryConf = new Configuration(false);
 
   protected static File assertCreateDir(File dir) {
     if(!dir.isDirectory()) {
@@ -831,7 +832,6 @@ public abstract class TestHDFSIntegrationBase {
       hiveUgi.doAs(new PrivilegedExceptionAction<Void>() {
         @Override
         public Void run() throws Exception {
-          Configuration sentryConf = new Configuration(false);
           sentryConf.set(SENTRY_HDFS_INTEGRATION_PATH_PREFIXES, 
MANAGED_PREFIXES);
           sentryProperties.put(HiveServerFactory.AUTHZ_PROVIDER_BACKEND,
               SimpleDBProviderBackend.class.getName());

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationTogglingConf.java
----------------------------------------------------------------------
diff --git 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationTogglingConf.java
 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationTogglingConf.java
new file mode 100644
index 0000000..e54ffce
--- /dev/null
+++ 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hdfs/TestHDFSIntegrationTogglingConf.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions
+ * and
+ * limitations under the License.
+*/
+
+package org.apache.sentry.tests.e2e.hdfs;
+
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.permission.FsAction;
+import org.apache.sentry.hdfs.SentryAuthorizationConstants;
+import org.apache.sentry.service.thrift.ServiceConstants;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.Statement;
+
+/**
+ * this test class includes tests to verify the behaviour of sentry server
+ * when the HDFS sync feature is toggled on/off
+ */
+public class TestHDFSIntegrationTogglingConf extends TestHDFSIntegrationBase {
+
+  private static long getSleepTimeAfterFollowerRestart(Configuration conf) {
+    long followerInitDelay = 
conf.getLong(ServiceConstants.ServerConfig.SENTRY_HMSFOLLOWER_INIT_DELAY_MILLS,
+            
ServiceConstants.ServerConfig.SENTRY_HMSFOLLOWER_INIT_DELAY_MILLS_DEFAULT);
+    long followerInterval = 
conf.getLong(ServiceConstants.ServerConfig.SENTRY_HMSFOLLOWER_INTERVAL_MILLS,
+            
ServiceConstants.ServerConfig.SENTRY_HMSFOLLOWER_INTERVAL_MILLS_DEFAULT);
+    long refreshIntervalMillisec = conf.getInt(
+            SentryAuthorizationConstants.CACHE_REFRESH_INTERVAL_KEY,
+            SentryAuthorizationConstants.CACHE_REFRESH_INTERVAL_DEFAULT);
+
+    return (followerInitDelay + followerInterval + refreshIntervalMillisec) * 
2;
+  }
+
+  private static void enableHdfsSync(int serverIndex) throws Exception {
+    Configuration newConfig = new Configuration(sentryConf);
+    newConfig.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES,
+            "org.apache.sentry.hdfs.SentryHDFSServiceProcessorFactory");
+    newConfig.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS,
+            "org.apache.sentry.hdfs.SentryPlugin");
+    
newConfig.set(ServiceConstants.ServerConfig.SENTRY_HMSFOLLOWER_INIT_DELAY_MILLS,
+            "1000");
+    sentryServer.restartHMSFollower(newConfig, serverIndex,
+            getSleepTimeAfterFollowerRestart(newConfig));
+  }
+
+  private static void disableHdfsSync(int serverIndex) throws Exception {
+    Configuration newConfig = new Configuration(sentryConf);
+    newConfig.set(ServiceConstants.ServerConfig.PROCESSOR_FACTORIES, "");
+    newConfig.set(ServiceConstants.ServerConfig.SENTRY_POLICY_STORE_PLUGINS, 
"");
+    
newConfig.set(ServiceConstants.ServerConfig.SENTRY_HMSFOLLOWER_INIT_DELAY_MILLS,
+            "1000");
+
+    sentryServer.restartHMSFollower(newConfig, serverIndex,
+            getSleepTimeAfterFollowerRestart(newConfig));
+  }
+
+  @BeforeClass
+  public static void setup() throws Exception {
+    hdfsSyncEnabled = true;
+    TestHDFSIntegrationBase.setup();
+  }
+
+  /**
+   * Test makes sure that the namenode is not synced with the new change to 
HMS when
+   * processor and sentry_plugin for HDFS sync are not configured.
+   *
+   * @throws Throwable
+   */
+  @Test
+  public void testDisablingHDFSSync() throws Throwable {
+    disableHdfsSync(0);
+    dbNames = new String[]{"db1"};
+    roles = new String[]{"admin_role", "tab_role"};
+    admin = "hive";
+
+    Connection conn;
+    Statement stmt;
+    conn = hiveServer2.createConnection("hive", "hive");
+    stmt = conn.createStatement();
+    stmt.execute("create role admin_role");
+    stmt.execute("grant role admin_role to group hive");
+    stmt.execute("grant all on server server1 to role admin_role");
+
+    // db privileges
+    stmt.execute("create database db1");
+    stmt.execute("create role tab_role");
+    stmt.execute("grant role tab_role to group flume");
+    stmt.execute("create table db1.p2(id int)");
+
+    stmt.execute("use db1");
+    stmt.execute("grant all on table p2 to role tab_role");
+    stmt.execute("use default");
+    verifyOnAllSubDirs("/user/hive/warehouse/db1.db", FsAction.ALL, "hbase", 
false);
+    verifyOnAllSubDirs("/user/hive/warehouse/db1.db/p2", FsAction.ALL, 
"flume", false);
+    verifyOnPath("/user/hive/warehouse/db1.db", FsAction.ALL, "flume", false);
+
+    //Enabling HDFS sync back in sentry server
+    enableHdfsSync(0);
+  }
+
+  /**
+   * Test makes sure that HDFS sync configurations in sentryserver are toggled 
multiple times.
+   * <ul>
+   * <li>When processor and sentry_plugin for HDFS sync are configured,
+   * Namenode should have all the HMS path and permission updates.</li>
+   * <li>When processor and sentry_plugin for HDFS sync are configured,
+   * Namenode should not have the HMS path updates.</li>
+   * <li>When processor and sentry_plugin for HDFS sync are configured again,
+   * Namenode should not have the HMS path updates by getting HMS full snapshot
+   * from sentry server.</li>
+   * </ul>
+   *
+   * @throws Throwable
+   */
+  @Test
+  public void testEnablingDisablingHDFSSync() throws Throwable {
+    dbNames = new String[]{"db1", "db6"};
+    roles = new String[]{"admin_role", "db_role", "tab_role", "p1_admin"};
+    admin = "hive";
+
+    Connection conn;
+    Statement stmt;
+    conn = hiveServer2.createConnection("hive", "hive");
+    stmt = conn.createStatement();
+    stmt.execute("create role admin_role");
+    stmt.execute("grant role admin_role to group hive");
+    stmt.execute("grant all on server server1 to role admin_role");
+    stmt.execute("create table p1 (s string) partitioned by (month int, day " +
+            "int)");
+    stmt.execute("alter table p1 add partition (month=1, day=1)");
+
+    // db privileges
+    stmt.execute("create database db1");
+    stmt.execute("create role db_role");
+    stmt.execute("create role tab_role");
+    stmt.execute("grant role db_role to group hbase");
+    stmt.execute("grant role tab_role to group flume");
+    stmt.execute("create table db1.p2(id int)");
+
+    stmt.execute("create role p1_admin");
+    stmt.execute("grant role p1_admin to group hbase");
+
+    // Verify default db is inaccessible initially
+    verifyOnAllSubDirs("/user/hive/warehouse", null, "hbase", false);
+
+    verifyOnAllSubDirs("/user/hive/warehouse/p1", null, "hbase", false);
+
+    stmt.execute("grant all on database db1 to role db_role");
+    stmt.execute("use db1");
+    stmt.execute("grant all on table p2 to role tab_role");
+    stmt.execute("use default");
+    verifyOnAllSubDirs("/user/hive/warehouse/db1.db", FsAction.ALL, "hbase", 
true);
+    verifyOnAllSubDirs("/user/hive/warehouse/db1.db/p2", FsAction.ALL, 
"hbase", true);
+    verifyOnAllSubDirs("/user/hive/warehouse/db1.db/p2", FsAction.ALL, 
"flume", true);
+    verifyOnPath("/user/hive/warehouse/db1.db", FsAction.ALL, "flume", false);
+
+    loadData(stmt);
+
+    verifyHDFSandMR(stmt);
+
+    //Disabling HDFS sync in sentry server
+    disableHdfsSync(0);
+
+    stmt.execute("revoke all on database db1 from role db_role");
+    verifyOnAllSubDirs("/user/hive/warehouse/db1.db", FsAction.ALL, "hbase", 
false);
+
+    // create a table and grant all to db_role
+    stmt.execute("create database db6");
+    stmt.execute("grant all on database db6 to role db_role");
+
+    // verify that db_role does not have required ACL's as HDFS sync is 
disabled in sentry server.
+    verifyOnAllSubDirs("/user/hive/warehouse/db6.db", FsAction.ALL, "hbase", 
false);
+
+    //Create table in db6 and grant all privileges to tab role
+    stmt.execute("use db6");
+    stmt.execute("create table db6.p1(id int)");
+    stmt.execute("grant all on table db6.p1 to role tab_role");
+
+    // verify that tab_role does not have required permissions
+    verifyOnAllSubDirs("/user/hive/warehouse/db6.db/p1", FsAction.ALL, 
"flume", false);
+
+    //Enabling HDFS sync in sentry server
+    enableHdfsSync(0);
+
+    // As HDFS sync is re-enabled, sentry should take full snapshot and send 
it NN.
+    // db_role and tab_role should have required privileges.
+    // Checks below will make sure that sentry/NN have the updates that 
happened
+    // to HMS objects when HDFS was disabled.
+    verifyOnAllSubDirs("/user/hive/warehouse/db6.db", FsAction.ALL, "hbase", 
true);
+    verifyOnAllSubDirs("/user/hive/warehouse/db6.db/p1", FsAction.ALL, 
"flume", true);
+
+    stmt.close();
+    conn.close();
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/InternalSentrySrv.java
----------------------------------------------------------------------
diff --git 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/InternalSentrySrv.java
 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/InternalSentrySrv.java
index e64f5cd..6ebb273 100644
--- 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/InternalSentrySrv.java
+++ 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/InternalSentrySrv.java
@@ -151,6 +151,17 @@ public class InternalSentrySrv implements SentrySrv {
   }
 
   @Override
+  public void restartHMSFollower(Configuration newConf, int serverNum,
+      long sleepTime) throws Exception {
+    if (!isActive) {
+      throw new IllegalStateException("SentrySrv is no longer active");
+    }
+    SentryService sentryServer = sentryServers.get(serverNum);
+    sentryServer.restartHMSFollower(newConf);
+    Thread.sleep(sleepTime);
+  }
+
+  @Override
   public void stopAll() throws Exception {
     boolean cleanStop = true;
     if (!isActive) {

http://git-wip-us.apache.org/repos/asf/sentry/blob/94cfb1b4/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrv.java
----------------------------------------------------------------------
diff --git 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrv.java
 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrv.java
index 9139706..0e82b86 100644
--- 
a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrv.java
+++ 
b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrv.java
@@ -17,6 +17,7 @@
  */
 package org.apache.sentry.tests.e2e.minisentry;
 
+import org.apache.hadoop.conf.Configuration;
 import org.apache.sentry.service.thrift.SentryService;
 
 public interface SentrySrv {
@@ -36,6 +37,15 @@ public interface SentrySrv {
   void start(int serverNum) throws Exception ;
 
   /**
+   * retart HMSFollower with new configuration
+   * @param newConf new configuration
+   * @param serverNum Server number
+   * @throws Exception
+   */
+  void restartHMSFollower(Configuration newConf, int serverNum,
+      long sleepTime) throws Exception ;
+
+  /**
    * Stop all the Sentry servers
    * @throws Exception
    */

Reply via email to