You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sentry.apache.org by pr...@apache.org on 2015/02/20 09:44:44 UTC
incubator-sentry git commit: SENTRY-648: Add e2e tests for Sentry HA
(Prasad Mujumdar reviewed by Lenni Kuff)
Repository: incubator-sentry
Updated Branches:
refs/heads/master 427705ff8 -> 36274c25c
SENTRY-648: Add e2e tests for Sentry HA (Prasad Mujumdar reviewed by Lenni Kuff)
Project: http://git-wip-us.apache.org/repos/asf/incubator-sentry/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-sentry/commit/36274c25
Tree: http://git-wip-us.apache.org/repos/asf/incubator-sentry/tree/36274c25
Diff: http://git-wip-us.apache.org/repos/asf/incubator-sentry/diff/36274c25
Branch: refs/heads/master
Commit: 36274c25c14370917981a53f63d8348a0c4a8bc4
Parents: 427705f
Author: Prasad Mujumdar <pr...@apache.org>
Authored: Fri Feb 20 00:38:32 2015 -0800
Committer: Prasad Mujumdar <pr...@apache.org>
Committed: Fri Feb 20 00:38:32 2015 -0800
----------------------------------------------------------------------
.../db/service/persistent/ServiceManager.java | 24 ++-
.../thrift/HAClientInvocationHandler.java | 50 +++---
.../sentry/service/thrift/SentryService.java | 24 ++-
.../sentry/service/thrift/ServiceConstants.java | 2 +-
.../sentry/tests/e2e/ha/TestHaEnd2End.java | 171 +++++++++++++++++++
.../AbstractTestWithStaticConfiguration.java | 62 ++++---
.../tests/e2e/minisentry/InternalSentrySrv.java | 164 ++++++++++++++++++
.../sentry/tests/e2e/minisentry/SentrySrv.java | 79 +++++++++
.../tests/e2e/minisentry/SentrySrvFactory.java | 45 +++++
9 files changed, 564 insertions(+), 57 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceManager.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceManager.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceManager.java
index 2274f00..a970b92 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceManager.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/provider/db/service/persistent/ServiceManager.java
@@ -29,11 +29,20 @@ import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.curator.x.discovery.ServiceProvider;
import org.apache.curator.x.discovery.details.InstanceSerializer;
import org.apache.hadoop.net.NetUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+/***
+ * ServerManager handles registration of the Sentry service for Curator service
+ * discovery. Each server registers with ZK and add its host:port details which
+ * is used by the clients to discover available servers
+ */
public class ServiceManager {
-
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(ServiceManager.class);
private HAContext haContext;
private ServiceProvider<Void> serviceProvider;
+ private ServiceDiscovery<Void> serviceDiscovery;
public ServiceManager(HAContext haContext) throws IOException {
this.haContext = haContext;
@@ -47,7 +56,7 @@ public class ServiceManager {
curatorFramework.start();
}
InstanceSerializer<Void> instanceSerializer = new FixedJsonInstanceSerializer<Void>(Void.class);
- ServiceDiscovery<Void> serviceDiscovery = ServiceDiscoveryBuilder.<Void>builder(Void.class)
+ serviceDiscovery = ServiceDiscoveryBuilder.<Void>builder(Void.class)
.basePath(HAContext.SENTRY_SERVICE_REGISTER_NAMESPACE)
.serializer(instanceSerializer)
.client(curatorFramework)
@@ -80,4 +89,15 @@ public class ServiceManager {
public static InetSocketAddress convertServiceInstance(ServiceInstance<?> service) {
return NetUtils.createSocketAddr(service.getAddress(),service.getPort());
}
+
+ public void close() {
+ try {
+ serviceProvider.close();
+ serviceDiscovery.close();
+ haContext.getCuratorFramework().close();
+ LOGGER.debug("Closed ZK resources");
+ } catch (IOException e) {
+ LOGGER.warn("Error closing the service manager", e);
+ }
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/HAClientInvocationHandler.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/HAClientInvocationHandler.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/HAClientInvocationHandler.java
index c6e265f..1dea938 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/HAClientInvocationHandler.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/HAClientInvocationHandler.java
@@ -25,7 +25,6 @@ import java.net.InetSocketAddress;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.security.SecurityUtil;
-
import org.apache.curator.x.discovery.ServiceInstance;
import org.apache.sentry.SentryUserException;
import org.apache.sentry.provider.db.service.persistent.HAContext;
@@ -43,7 +42,7 @@ public class HAClientInvocationHandler implements InvocationHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(HAClientInvocationHandler.class);
private final Configuration conf;
- private final ServiceManager manager;
+ private ServiceManager manager;
private ServiceInstance<Void> currentServiceInstance;
private SentryPolicyServiceClient client = null;
@@ -51,7 +50,6 @@ public class HAClientInvocationHandler implements InvocationHandler {
public HAClientInvocationHandler(Configuration conf) throws Exception {
this.conf = conf;
- manager = new ServiceManager(new HAContext(conf));
checkClientConf();
renewSentryClient();
}
@@ -87,25 +85,35 @@ public class HAClientInvocationHandler implements InvocationHandler {
}
private void renewSentryClient() throws IOException {
- while (true) {
- if (client != null) {
- client.close();
- }
- currentServiceInstance = manager.getServiceInstance();
- if (currentServiceInstance == null) {
- throw new IOException("No avaiable node.");
- }
- InetSocketAddress serverAddress =
- ServiceManager.convertServiceInstance(currentServiceInstance);
- conf.set(ServiceConstants.ClientConfig.SERVER_RPC_ADDRESS, serverAddress.getHostName());
- conf.setInt(ServiceConstants.ClientConfig.SERVER_RPC_PORT, serverAddress.getPort());
- try {
- client = new SentryPolicyServiceClientDefaultImpl(conf);
- break;
- } catch (IOException e) {
- manager.reportError(currentServiceInstance);
- LOGGER.info("Transport exception while opening transport:", e, e.getMessage());
+ try {
+ manager = new ServiceManager(new HAContext(conf));
+ } catch (Exception e1) {
+ throw new IOException("Failed to extract Sentry node info from zookeeper", e1);
+ }
+
+ try {
+ while (true) {
+ if (client != null) {
+ client.close();
+ }
+ currentServiceInstance = manager.getServiceInstance();
+ if (currentServiceInstance == null) {
+ throw new IOException("No avaiable node.");
+ }
+ InetSocketAddress serverAddress =
+ ServiceManager.convertServiceInstance(currentServiceInstance);
+ conf.set(ServiceConstants.ClientConfig.SERVER_RPC_ADDRESS, serverAddress.getHostName());
+ conf.setInt(ServiceConstants.ClientConfig.SERVER_RPC_PORT, serverAddress.getPort());
+ try {
+ client = new SentryPolicyServiceClientDefaultImpl(conf);
+ break;
+ } catch (IOException e) {
+ manager.reportError(currentServiceInstance);
+ LOGGER.info("Transport exception while opening transport:", e, e.getMessage());
+ }
}
+ } finally {
+ manager.close();
}
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/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 02788aa..0b4b39a 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
@@ -85,7 +85,7 @@ public class SentryService implements Callable {
private final String[] principalParts;
private final String keytab;
private final ExecutorService serviceExecutor;
- private Future future;
+ private Future serviceStatus;
private TServer thriftServer;
private Status status;
private int webServerPort;
@@ -239,6 +239,7 @@ public class SentryService implements Callable {
private void stopSentryWebServer() throws Exception{
if( sentryWebServer != null) {
sentryWebServer.stop();
+ sentryWebServer = null;
}
}
@@ -257,7 +258,7 @@ public class SentryService implements Callable {
}
LOGGER.info("Attempting to start...");
status = Status.STARTED;
- future = serviceExecutor.submit(this);
+ serviceStatus = serviceExecutor.submit(this);
}
public synchronized void stop() throws Exception{
@@ -295,6 +296,16 @@ public class SentryService implements Callable {
LOGGER.info("Stopped...");
}
+ // wait for the service thread to finish execution
+ public synchronized void waitForShutDown() {
+ LOGGER.info("Waiting on future.get()");
+ try {
+ serviceStatus.get();
+ } catch (Exception e) {
+ LOGGER.debug("Error during the shutdown", e);
+ }
+ }
+
private MultiException addMultiException(MultiException exception, Exception e) {
if(exception == null){
exception = new MultiException();
@@ -355,9 +366,9 @@ public class SentryService implements Callable {
File configFile = null;
if (configFileName == null || commandLine.hasOption("h") || commandLine.hasOption("help")) {
// print usage
- HelpFormatter formatter = new HelpFormatter();
- formatter.printHelp("sentry --command service", options);
- System.exit(-1);
+ HelpFormatter formatter = new HelpFormatter();
+ formatter.printHelp("sentry --command service", options);
+ System.exit(-1);
} else if(!((configFile = new File(configFileName)).isFile() && configFile.canRead())) {
throw new IllegalArgumentException("Cannot read configuration file " + configFile);
}
@@ -378,8 +389,7 @@ public class SentryService implements Callable {
// Let's wait on the service to stop
try {
- LOGGER.info("Waiting on future.get()");
- server.future.get();
+ server.waitForShutDown();
} finally {
server.serviceExecutor.shutdown();
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
----------------------------------------------------------------------
diff --git a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
index ddc5930..77e1f60 100644
--- a/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
+++ b/sentry-provider/sentry-provider-db/src/main/java/org/apache/sentry/service/thrift/ServiceConstants.java
@@ -121,7 +121,7 @@ public class ServiceConstants {
public static final String SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS = SENTRY_HA_ZK_PROPERTY_PREFIX + "session.sleep.between.retries.ms";
public static final int SENTRY_HA_ZOOKEEPER_SLEEP_BETWEEN_RETRIES_MS_DEFAULT = 100;
public static final String SENTRY_HA_ZOOKEEPER_NAMESPACE = SENTRY_HA_ZK_PROPERTY_PREFIX + "namespace";
- public static final String SENTRY_HA_ZOOKEEPER_NAMESPACE_DEFAULT = "/sentry";
+ public static final String SENTRY_HA_ZOOKEEPER_NAMESPACE_DEFAULT = "sentry";
public static final ImmutableMap<String, String> SENTRY_STORE_DEFAULTS =
ImmutableMap.<String, String>builder()
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/ha/TestHaEnd2End.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/ha/TestHaEnd2End.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/ha/TestHaEnd2End.java
new file mode 100644
index 0000000..78894d1
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/ha/TestHaEnd2End.java
@@ -0,0 +1,171 @@
+/**
+ * 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.ha;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+import org.apache.sentry.provider.db.SentryAccessDeniedException;
+import org.apache.sentry.provider.file.PolicyFile;
+import org.apache.sentry.tests.e2e.hive.AbstractTestWithStaticConfiguration;
+import org.apache.sentry.tests.e2e.hive.StaticUserGroup;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import com.google.common.io.Resources;
+
+/**
+ * End2End tests with Sentry service HA enabled.
+ */
+public class TestHaEnd2End extends AbstractTestWithStaticConfiguration {
+
+ private final String SINGLE_TYPE_DATA_FILE_NAME = "kv1.dat";
+ private File dataFile;
+ private PolicyFile policyFile;
+
+ @BeforeClass
+ public static void setupTestStaticConfiguration() throws Exception {
+ useSentryService = true;
+ enableSentryHA = true;
+ AbstractTestWithStaticConfiguration.setupTestStaticConfiguration();
+ }
+
+ @Override
+ @Before
+ public void setup() throws Exception {
+ super.setupAdmin();
+ super.setup();
+ dataFile = new File(dataDir, SINGLE_TYPE_DATA_FILE_NAME);
+ FileOutputStream to = new FileOutputStream(dataFile);
+ Resources.copy(Resources.getResource(SINGLE_TYPE_DATA_FILE_NAME), to);
+ to.close();
+ policyFile = PolicyFile.setAdminOnServer1(ADMINGROUP);
+ }
+
+ /**
+ * Basic test with two Sentry service running.
+ * @throws Exception
+ */
+ @Test
+ public void testBasic() throws Exception {
+ Connection connection = context.createConnection(ADMIN1);
+ Statement statement = context.createStatement(connection);
+ statement.execute("CREATE TABLE t1 (c1 string)");
+ statement.execute("CREATE ROLE user_role");
+ statement.execute("GRANT SELECT ON TABLE t1 TO ROLE user_role");
+ statement.execute("GRANT ROLE user_role TO GROUP " + USERGROUP1);
+ statement.close();
+ connection.close();
+ connection = context.createConnection(USER1_1);
+ statement = context.createStatement(connection);
+ context.assertSentryException(statement, "CREATE ROLE r2",
+ SentryAccessDeniedException.class.getSimpleName());
+ // test default of ALL
+ statement.execute("SELECT * FROM t1");
+ // test a specific role
+ statement.execute("SET ROLE user_role");
+ statement.execute("SELECT * FROM t1");
+
+ // test ALL
+ statement.execute("SET ROLE ALL");
+ statement.execute("SELECT * FROM t1");
+ statement.close();
+ connection.close();
+
+ // cleanup
+ connection = context.createConnection(ADMIN1);
+ statement = context.createStatement(connection);
+ statement.execute("DROP ROLE user_role");
+ statement.close();
+ connection.close();
+ }
+
+ /**
+ * Test service failover. Run Sentry operations with shutting down one or more
+ * of the services.
+ * @throws Exception
+ */
+ @Test
+ public void testFailover() throws Exception {
+ String roleName1 = "test_role_1";
+ String roleName2 = "test_role_2";
+ String roleName3 = "test_role_3";
+
+ dropDb(ADMIN1, DB1);
+ createDb(ADMIN1, DB1);
+ createTable(ADMIN1, DB1, dataFile, TBL1);
+
+ Connection adminCon = context.createConnection(ADMIN1);
+ Statement adminStmt = context.createStatement(adminCon);
+ // access the new databases
+ adminStmt.execute("use " + DB1);
+
+ // stop server1 and verify sentry continues to work
+ getSentrySrv().stop(0);
+ adminStmt.execute("CREATE ROLE " + roleName1);
+ verifyRoleExists(adminStmt, roleName1);
+
+ // restart server1 and stop server2
+ getSentrySrv().start(0);
+ getSentrySrv().stop(1);
+ adminStmt.execute("CREATE ROLE " + roleName2);
+ verifyRoleExists(adminStmt, roleName2);
+
+ // stop both servers and verify it fails
+ getSentrySrv().stop(0);
+ getSentrySrv().stop(1);
+ context.assertAuthzException(adminStmt, "CREATE ROLE " + roleName3);
+
+ getSentrySrv().start(0);
+ getSentrySrv().start(1);
+ adminStmt.execute("CREATE ROLE " + roleName3);
+ verifyRoleExists(adminStmt, roleName3);
+
+ // cleanup
+
+ dropDb(ADMIN1, DB1);
+ adminStmt.execute("DROP ROLE " + roleName1);
+ adminStmt.execute("DROP ROLE " + roleName2);
+ adminStmt.execute("DROP ROLE " + roleName3);
+ adminStmt.close();
+ adminCon.close();
+
+ }
+
+ private void verifyRoleExists(Statement statement, String roleName)
+ throws Exception {
+ ResultSet resultSet = null;
+ try {
+ resultSet = statement.executeQuery("SHOW ROLES ");
+ while (resultSet.next()) {
+ if (roleName.equalsIgnoreCase(resultSet.getString(1))) {
+ return;
+ }
+ }
+ throw new Exception("Role " + roleName + " does not exist");
+ } finally {
+ if (resultSet != null) {
+ resultSet.close();
+ }
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
index c68873e..3a8a6ef 100644
--- a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/hive/AbstractTestWithStaticConfiguration.java
@@ -49,15 +49,16 @@ import org.apache.sentry.policy.db.DBModelAuthorizables;
import org.apache.sentry.provider.db.SimpleDBProviderBackend;
import org.apache.sentry.provider.db.service.thrift.SentryPolicyServiceClient;
import org.apache.sentry.provider.file.PolicyFile;
-import org.apache.sentry.service.thrift.SentryService;
import org.apache.sentry.service.thrift.SentryServiceClientFactory;
-import org.apache.sentry.service.thrift.SentryServiceFactory;
import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig;
import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
import org.apache.sentry.tests.e2e.hive.fs.DFS;
import org.apache.sentry.tests.e2e.hive.fs.DFSFactory;
import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServer;
import org.apache.sentry.tests.e2e.hive.hiveserver.HiveServerFactory;
+import org.apache.sentry.tests.e2e.minisentry.SentrySrvFactory;
+import org.apache.sentry.tests.e2e.minisentry.SentrySrvFactory.SentrySrvType;
+import org.apache.sentry.tests.e2e.minisentry.SentrySrv;
import org.apache.tools.ant.util.StringUtils;
import org.junit.After;
import org.junit.AfterClass;
@@ -108,6 +109,7 @@ public abstract class AbstractTestWithStaticConfiguration {
protected static final String SERVER_HOST = "localhost";
private static final String EXTERNAL_SENTRY_SERVICE = "sentry.e2etest.external.sentry";
protected static final String EXTERNAL_HIVE_LIB = "sentry.e2etest.hive.lib";
+ private static final String ENABLE_SENTRY_HA = "sentry.e2etest.enable.service.ha";
protected static boolean policyOnHdfs = false;
protected static boolean useSentryService = false;
@@ -127,8 +129,9 @@ public abstract class AbstractTestWithStaticConfiguration {
protected static HiveServerFactory.HiveServer2Type hiveServer2Type;
protected static DFS dfs;
protected static Map<String, String> properties;
- protected static SentryService sentryServer;
+ protected static SentrySrv sentryServer;
protected static Configuration sentryConf;
+ protected static boolean enableSentryHA = false;
protected static Context context;
protected final String semanticException = "SemanticException No valid privileges";
@@ -209,7 +212,7 @@ public abstract class AbstractTestWithStaticConfiguration {
PolicyFile policyFile = PolicyFile.setAdminOnServer1(ADMIN1)
.setUserGroupMapping(StaticUserGroup.getStaticMapping());
policyFile.write(policyFileLocation);
-
+
String policyURI;
if (policyOnHdfs) {
String dfsUri = FileSystem.getDefaultUri(fileSystem.getConf()).toString();
@@ -220,8 +223,11 @@ public abstract class AbstractTestWithStaticConfiguration {
} else {
policyURI = policyFileLocation.getPath();
}
-
+
boolean startSentry = new Boolean(System.getProperty(EXTERNAL_SENTRY_SERVICE, "false"));
+ if ("true".equalsIgnoreCase(System.getProperty(ENABLE_SENTRY_HA, "false"))) {
+ enableSentryHA = true;
+ }
if (useSentryService && (!startSentry)) {
setupSentryService();
}
@@ -240,8 +246,8 @@ public abstract class AbstractTestWithStaticConfiguration {
}
public static HiveServer create(Map<String, String> properties,
- File baseDir, File confDir, File logDir, String policyFile,
- FileSystem fileSystem) throws Exception {
+ File baseDir, File confDir, File logDir, String policyFile,
+ FileSystem fileSystem) throws Exception {
String type = properties.get(HiveServerFactory.HIVESERVER2_TYPE);
if(type == null) {
type = System.getProperty(HiveServerFactory.HIVESERVER2_TYPE);
@@ -291,7 +297,7 @@ public abstract class AbstractTestWithStaticConfiguration {
.entrySet()) {
for (String roleNames : groupEntry.getValue()) {
for (String roleName : roleNames.split(",")) {
- statement.execute("GRANT ROLE " + roleName + " TO GROUP " + groupEntry.getKey());
+ statement.execute("GRANT ROLE " + roleName + " TO GROUP " + groupEntry.getKey());
}
}
}
@@ -359,7 +365,7 @@ public abstract class AbstractTestWithStaticConfiguration {
properties.put(ConfVars.HIVE_AUTHORIZATION_TASK_FACTORY.varname,
SentryHiveAuthorizationTaskFactoryImpl.class.getName());
properties
- .put(ConfVars.HIVE_SERVER2_THRIFT_MIN_WORKER_THREADS.varname, "2");
+ .put(ConfVars.HIVE_SERVER2_THRIFT_MIN_WORKER_THREADS.varname, "2");
properties.put(ServerConfig.SECURITY_MODE, ServerConfig.SECURITY_MODE_NONE);
properties.put(ServerConfig.ADMIN_GROUPS, ADMINGROUP);
properties.put(ServerConfig.RPC_ADDRESS, SERVER_HOST);
@@ -368,22 +374,30 @@ public abstract class AbstractTestWithStaticConfiguration {
properties.put(ServerConfig.SENTRY_STORE_JDBC_URL,
"jdbc:derby:;databaseName=" + baseDir.getPath()
- + "/sentrystore_db;create=true");
+ + "/sentrystore_db;create=true");
properties.put(ServerConfig.SENTRY_STORE_GROUP_MAPPING, ServerConfig.SENTRY_STORE_LOCAL_GROUP_MAPPING);
properties.put(ServerConfig.SENTRY_STORE_GROUP_MAPPING_RESOURCE, policyFileLocation.getPath());
properties.put(ServerConfig.RPC_MIN_THREADS, "3");
for (Map.Entry<String, String> entry : properties.entrySet()) {
sentryConf.set(entry.getKey(), entry.getValue());
}
- sentryServer = new SentryServiceFactory().create(sentryConf);
- properties.put(ClientConfig.SERVER_RPC_ADDRESS, sentryServer.getAddress()
+ sentryServer = SentrySrvFactory.create(
+ SentrySrvType.INTERNAL_SERVER, sentryConf, enableSentryHA ? 2 : 1);
+ properties.put(ClientConfig.SERVER_RPC_ADDRESS, sentryServer.get(0)
+ .getAddress()
.getHostName());
- sentryConf.set(ClientConfig.SERVER_RPC_ADDRESS, sentryServer.getAddress()
+ sentryConf.set(ClientConfig.SERVER_RPC_ADDRESS, sentryServer.get(0)
+ .getAddress()
.getHostName());
properties.put(ClientConfig.SERVER_RPC_PORT,
- String.valueOf(sentryServer.getAddress().getPort()));
+ String.valueOf(sentryServer.get(0).getAddress().getPort()));
sentryConf.set(ClientConfig.SERVER_RPC_PORT,
- String.valueOf(sentryServer.getAddress().getPort()));
+ String.valueOf(sentryServer.get(0).getAddress().getPort()));
+ if (enableSentryHA) {
+ properties.put(ClientConfig.SERVER_HA_ENABLED, "true");
+ properties.put(ClientConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
+ sentryServer.getZKQuorum());
+ }
startSentryService();
if (setMetastoreListener) {
properties.put(HiveConf.ConfVars.METASTORE_EVENT_LISTENERS.varname,
@@ -393,21 +407,14 @@ public abstract class AbstractTestWithStaticConfiguration {
}
private static void startSentryService() throws Exception {
- sentryServer.start();
- final long start = System.currentTimeMillis();
- while (!sentryServer.isRunning()) {
- Thread.sleep(1000);
- if (System.currentTimeMillis() - start > 60000L) {
- throw new TimeoutException("Server did not start after 60 seconds");
- }
- }
+ sentryServer.startAll();
}
public static SentryPolicyServiceClient getSentryClient() throws Exception {
if (sentryServer == null) {
throw new IllegalAccessException("Sentry service not initialized");
}
- return SentryServiceClientFactory.create(sentryServer.getConf());
+ return SentryServiceClientFactory.create(sentryServer.get(0).getConf());
}
@Before
@@ -475,8 +482,7 @@ public abstract class AbstractTestWithStaticConfiguration {
}
if (sentryServer != null) {
- sentryServer.stop();
- sentryServer = null;
+ sentryServer.close();
sentryServer = null;
}
@@ -497,4 +503,8 @@ public abstract class AbstractTestWithStaticConfiguration {
context.close();
}
}
+
+ public static SentrySrv getSentrySrv() {
+ return sentryServer;
+ }
}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/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
new file mode 100644
index 0000000..68bc9ee
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/InternalSentrySrv.java
@@ -0,0 +1,164 @@
+/**
+ * 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.minisentry;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.curator.test.TestingServer;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.sentry.service.thrift.SentryService;
+import org.apache.sentry.service.thrift.SentryServiceFactory;
+import org.apache.sentry.service.thrift.ServiceConstants.ClientConfig;
+import org.apache.sentry.service.thrift.ServiceConstants.ServerConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.Lists;
+
+public class InternalSentrySrv implements SentrySrv {
+
+ private List<SentryService> sentryServers = Lists.newArrayList();
+ private static TestingServer zkServer; // created only if in case of HA
+ private static final Logger LOGGER = LoggerFactory
+ .getLogger(InternalSentrySrv.class);
+ private boolean isActive = false;
+
+ public InternalSentrySrv(Configuration sentryConf, int numServers)
+ throws Exception {
+ // Enable HA when numServers is more that 1, start Curator TestingServer
+ if (numServers > 1) {
+ zkServer = new TestingServer();
+ zkServer.start();
+ sentryConf.setBoolean(ServerConfig.SENTRY_HA_ENABLED, true);
+ sentryConf.set(ServerConfig.SENTRY_HA_ZOOKEEPER_QUORUM,
+ zkServer.getConnectString());
+ } else if (numServers <= 0) {
+ throw new IllegalArgumentException("Invalid number of Servers: "
+ + numServers + " ,must be > 0");
+ }
+ for (int count = 0; count < numServers; count++) {
+ Configuration servConf = new Configuration(sentryConf);
+ SentryService sentryServer = new SentryServiceFactory().create(servConf);
+ servConf.set(ClientConfig.SERVER_RPC_ADDRESS, sentryServer.getAddress()
+ .getHostName());
+ servConf.setInt(ClientConfig.SERVER_RPC_PORT, sentryServer.getAddress()
+ .getPort());
+ sentryServers.add(sentryServer);
+ }
+ isActive = true;
+ }
+
+ @Override
+ public void startAll() throws Exception {
+ if (!isActive) {
+ throw new IllegalStateException("SentrySrv is no longer active");
+ }
+ for (int sentryServerNum = 0; sentryServerNum < sentryServers.size(); sentryServerNum++) {
+ start(sentryServerNum);
+ }
+ }
+
+ @Override
+ public void start(int serverNum) throws Exception {
+ if (!isActive) {
+ throw new IllegalStateException("SentrySrv is no longer active");
+ }
+ SentryService sentryServer = sentryServers.get(serverNum);
+ sentryServer.start();
+
+ // wait for startup
+ final long start = System.currentTimeMillis();
+ while (!sentryServer.isRunning()) {
+ Thread.sleep(1000);
+ if (System.currentTimeMillis() - start > 60000L) {
+ throw new TimeoutException("Server did not start after 60 seconds");
+ }
+ }
+ }
+
+ @Override
+ public void stopAll() throws Exception {
+ boolean cleanStop = true;
+ if (!isActive) {
+ throw new IllegalStateException("SentrySrv is no longer active");
+ }
+ for (int sentryServerNum = 0; sentryServerNum < sentryServers.size(); sentryServerNum++) {
+ try {
+ stop(sentryServerNum);
+ } catch (Exception e) {
+ LOGGER.error("Sentry Server " + sentryServerNum + " failed to stop");
+ cleanStop = false;
+ }
+ }
+ if (!cleanStop) {
+ throw new IllegalStateException(
+ "At least one of the servers failed to stop cleanly");
+ }
+ }
+
+ @Override
+ public void stop(int serverNum) throws Exception {
+ if (!isActive) {
+ throw new IllegalStateException("SentrySrv is no longer active");
+ }
+ SentryService sentryServer = sentryServers.get(serverNum);
+ sentryServer.stop();
+ sentryServer.waitForShutDown();
+ }
+
+ @Override
+ public void close() {
+ for (SentryService sentryServer : sentryServers) {
+ try {
+ sentryServer.stop();
+ } catch (Exception e) {
+ LOGGER.error("Error stoping Sentry service ", e);
+ }
+ }
+ if (zkServer != null) {
+ try {
+ zkServer.stop();
+ } catch (IOException e) {
+ LOGGER.warn("Error stoping ZK service ", e);
+ }
+ }
+ sentryServers.clear();
+ isActive = false;
+ }
+
+ @Override
+ public SentryService get(int serverNum) {
+ return sentryServers.get(serverNum);
+ }
+
+ @Override
+ public String getZKQuorum() throws Exception {
+ if (zkServer == null) {
+ throw new IOException("Sentry HA is not enabled");
+ }
+ return zkServer.getConnectString();
+ }
+
+ @Override
+ public boolean isHaEnabled() {
+ return zkServer != null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/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
new file mode 100644
index 0000000..e9ae5fa
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrv.java
@@ -0,0 +1,79 @@
+/**
+ * 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.minisentry;
+
+import org.apache.sentry.service.thrift.SentryService;
+
+public interface SentrySrv {
+
+ /**
+ * Start all the sentry services
+ * @throws Exception
+ */
+ public void startAll() throws Exception;
+
+ /**
+ * Start the given server
+ * @param serverNum
+ * - Server number (0 to N-1)
+ * @throws Exception
+ */
+ public void start(int serverNum) throws Exception ;
+
+ /**
+ * Stop all the Sentry servers
+ * @throws Exception
+ */
+ public void stopAll() throws Exception;
+
+ /**
+ * Stop the specified Sentry server
+ * @param serverNum
+ * - Server number (0 to N-1)
+ * @throws Exception
+ */
+ public void stop(int serverNum) throws Exception ;
+
+ /**
+ * Get the underlying Sentry service object
+ * @param serverNum
+ * - Server number (0 to N-1)
+ * @return
+ */
+ public SentryService get(int serverNum);
+
+ /**
+ * Get the ZK connection string
+ * @return
+ * @throws Exception
+ * - If HA is not enabled
+ */
+ public String getZKQuorum() throws Exception;
+
+ /**
+ * Stop all the nodes and ZK if started. The SentrySrv can't be reused once
+ * closed.
+ */
+ public void close();
+
+ /**
+ * Check if the sentry server is created with HA enabled.
+ * @return True - HA is enabled False - HA is not enabled
+ */
+ public boolean isHaEnabled();
+}
http://git-wip-us.apache.org/repos/asf/incubator-sentry/blob/36274c25/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrvFactory.java
----------------------------------------------------------------------
diff --git a/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrvFactory.java b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrvFactory.java
new file mode 100644
index 0000000..9381e88
--- /dev/null
+++ b/sentry-tests/sentry-tests-hive/src/test/java/org/apache/sentry/tests/e2e/minisentry/SentrySrvFactory.java
@@ -0,0 +1,45 @@
+/**
+ * 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.minisentry;
+
+import java.io.IOException;
+
+import org.apache.hadoop.conf.Configuration;
+
+public class SentrySrvFactory {
+
+ public static enum SentrySrvType {
+ INTERNAL_SERVER, EXTERNAL_SERVER
+ }
+
+ public static SentrySrv create(SentrySrvType srvType,
+ Configuration sentryConf)
+ throws Exception {
+ return create(srvType, sentryConf, 1);
+ }
+
+ public static SentrySrv create(SentrySrvType srvType,
+ Configuration sentryConf,
+ int numServers) throws Exception {
+ if (!srvType.equals(SentrySrvType.INTERNAL_SERVER)) {
+ throw new IOException("Server type " + srvType.name()
+ + " is not supported");
+ }
+ return new InternalSentrySrv(sentryConf, numServers);
+ }
+}