Skip to content
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 40 additions & 41 deletions jdbc/src/main/java/org/apache/zeppelin/jdbc/JDBCInterpreter.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import org.apache.zeppelin.interpreter.InterpreterException;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.apache.zeppelin.interpreter.KerberosInterpreter;
import org.apache.zeppelin.interpreter.ResultMessages;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.apache.zeppelin.jdbc.security.JDBCSecurityImpl;
Expand Down Expand Up @@ -89,7 +90,7 @@
* }
* </p>
*/
public class JDBCInterpreter extends Interpreter {
public class JDBCInterpreter extends KerberosInterpreter {

private Logger logger = LoggerFactory.getLogger(JDBCInterpreter.class);

Expand Down Expand Up @@ -147,12 +148,31 @@ public JDBCInterpreter(Properties property) {
maxLineResults = MAX_LINE_DEFAULT;
}

@Override
protected boolean runKerberosLogin() {
try {
UserGroupInformation.AuthenticationMethod authType = JDBCSecurityImpl.getAuthtype(property);
if (authType.equals(KERBEROS)) {

@zjffdu zjffdu Jul 5, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authType is not needed to check as runKerberosLogin would be only called when kerberos is enabled.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, make sense, removed unnecessary if condition.

if (UserGroupInformation.isLoginKeytabBased()) {
UserGroupInformation.getLoginUser().reloginFromKeytab();
} else if (UserGroupInformation.isLoginTicketBased()) {
UserGroupInformation.getLoginUser().reloginFromTicketCache();
}
}
} catch (Exception e) {
logger.error("Unable to run kinit for zeppelin", e);
return false;
}
return true;
}

public HashMap<String, Properties> getPropertiesMap() {
return basePropretiesMap;
}

@Override
public void open() {
super.open();
for (String propertyKey : property.stringPropertyNames()) {
logger.debug("propertyKey: {}", propertyKey);
String[] keyValue = propertyKey.split("\\.", 2);
Expand Down Expand Up @@ -190,6 +210,16 @@ public void open() {
setMaxLineResults();
}


protected boolean isKerboseEnabled() {
UserGroupInformation.AuthenticationMethod authType = JDBCSecurityImpl.getAuthtype(property);
if (authType.equals(KERBEROS)) {
return true;
}
return false;
}


private void setMaxLineResults() {
if (basePropretiesMap.containsKey(COMMON_KEY) &&
basePropretiesMap.get(COMMON_KEY).containsKey(MAX_LINE_KEY)) {
Expand Down Expand Up @@ -259,6 +289,7 @@ private void initConnectionPoolMap() {

@Override
public void close() {
super.close();
try {
initStatementMap();
initConnectionPoolMap();
Expand Down Expand Up @@ -709,49 +740,17 @@ private InterpreterResult executeSql(String propertyKey, String sql,
}
getJDBCConfiguration(user).removeStatement(paragraphId);
} catch (Throwable e) {
if (e.getCause() instanceof TTransportException &&
Throwables.getStackTraceAsString(e).contains("GSS") &&
getJDBCConfiguration(user).isConnectionInDBDriverPoolSuccessful(propertyKey)) {
return reLoginFromKeytab(propertyKey, sql, interpreterContext, interpreterResult);
} else {
logger.error("Cannot run " + sql, e);
String errorMsg = Throwables.getStackTraceAsString(e);
try {
closeDBPool(user, propertyKey);
} catch (SQLException e1) {
logger.error("Cannot close DBPool for user, propertyKey: " + user + propertyKey, e1);
}
interpreterResult.add(errorMsg);
return new InterpreterResult(Code.ERROR, interpreterResult.message());
}
}
return interpreterResult;
}

private InterpreterResult reLoginFromKeytab(String propertyKey, String sql,
InterpreterContext interpreterContext, InterpreterResult interpreterResult) {
String user = interpreterContext.getAuthenticationInfo().getUser();
try {
closeDBPool(user, propertyKey);
} catch (SQLException e) {
logger.error("Error, could not close DB pool in reLoginFromKeytab ", e);
}
UserGroupInformation.AuthenticationMethod authType =
JDBCSecurityImpl.getAuthtype(property);
if (authType.equals(KERBEROS)) {
logger.error("Cannot run " + sql, e);
String errorMsg = Throwables.getStackTraceAsString(e);
try {
if (UserGroupInformation.isLoginKeytabBased()) {
UserGroupInformation.getLoginUser().reloginFromKeytab();
} else if (UserGroupInformation.isLoginTicketBased()) {
UserGroupInformation.getLoginUser().reloginFromTicketCache();
}
} catch (IOException e) {
logger.error("Cannot reloginFromKeytab " + sql, e);
interpreterResult.add(e.getMessage());
return new InterpreterResult(Code.ERROR, interpreterResult.message());
closeDBPool(user, propertyKey);
} catch (SQLException e1) {
logger.error("Cannot close DBPool for user, propertyKey: " + user + propertyKey, e1);
}
interpreterResult.add(errorMsg);
return new InterpreterResult(Code.ERROR, interpreterResult.message());
}
return executeSql(propertyKey, sql, interpreterContext);
return interpreterResult;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,17 +57,14 @@ public ShellInterpreter(Properties property) {

@Override

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can move createSecureConfiguration from ShellSecurityImpl to ShellInterpreter, then ShellSecurityImpl could be deleted

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, done.

public void open() {
super.open();
LOGGER.info("Command timeout property: {}", getProperty(TIMEOUT_PROPERTY));
executors = new ConcurrentHashMap<>();
if (!StringUtils.isAnyEmpty(getProperty("zeppelin.shell.auth.type"))) {
startKerberosLoginThread();
}
}

@Override
public void close() {
shutdownExecutorService();

super.close();
for (String executorKey : executors.keySet()) {
DefaultExecutor executor = executors.remove(executorKey);
if (executor != null) {
Expand Down Expand Up @@ -171,4 +168,13 @@ protected boolean runKerberosLogin() {
return true;
}

@Override
protected boolean isKerboseEnabled() {
if (!StringUtils.isAnyEmpty(getProperty("zeppelin.shell.auth.type")) && getProperty(
"zeppelin.shell.auth.type").equalsIgnoreCase("kerberos")) {
return true;
}
return false;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@
public abstract class KerberosInterpreter extends Interpreter {

private Integer kinitFailCount = 0;
protected ScheduledExecutorService scheduledExecutorService;
public static Logger logger = LoggerFactory.getLogger(KerberosInterpreter.class);
private ScheduledExecutorService scheduledExecutorService;
private static Logger logger = LoggerFactory.getLogger(KerberosInterpreter.class);

public KerberosInterpreter(Properties property) {
super(property);
Expand All @@ -48,23 +48,38 @@ public KerberosInterpreter(Properties property) {
@ZeppelinApi
protected abstract boolean runKerberosLogin();

public String getKerberosRefreshInterval() {
@ZeppelinApi
protected abstract boolean isKerboseEnabled();

public void open() {
if (isKerboseEnabled()) {
startKerberosLoginThread();
}
}

public void close() {
if (isKerboseEnabled()) {
shutdownExecutorService();
}
}

private String getKerberosRefreshInterval() {
if (System.getenv("KERBEROS_REFRESH_INTERVAL") == null) {

@zjffdu zjffdu Jul 5, 2017

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to add javadoc for KerberosInterpreter.java to explain the internal mechanism of it. So basically I believe user need to do 3 things to extend KerberosInterpreter.

  • implement runKerberosLogin
  • implement isKerboseEnabled
  • define KERBEROS_REFRESH_INTERVAL in interpreter setting. Maybe we could also add abstract method like getKerborseRefreshInterval to enforce its sub class to implement it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, have added isKerboseEnabled in javadoc.
For KERBEROS_REFRESH_INTERVAL I think all interpreters can share a common its value defined in zeppelin-env.sh (https://github.com/apache/zeppelin/blob/master/conf/zeppelin-env.sh.template#L58-L59) instead of having it at interpreter level, and increasing the complexity (number of lines) of interpreter config.

return "1d";
} else {
return System.getenv("KERBEROS_REFRESH_INTERVAL");
}
}

public Integer kinitFailThreshold() {
private Integer kinitFailThreshold() {
if (System.getenv("KINIT_FAIL_THRESHOLD") == null) {
return 5;
} else {
return new Integer(System.getenv("KINIT_FAIL_THRESHOLD"));
}
}

public Long getTimeAsMs(String time) {
private Long getTimeAsMs(String time) {
if (time == null) {
logger.error("Cannot convert to time value.", time);
time = "1d";
Expand All @@ -86,7 +101,7 @@ public Long getTimeAsMs(String time) {
suffix != null ? Constants.TIME_SUFFIXES.get(suffix) : TimeUnit.MILLISECONDS);
}

protected ScheduledExecutorService startKerberosLoginThread() {
private ScheduledExecutorService startKerberosLoginThread() {
scheduledExecutorService = Executors.newScheduledThreadPool(1);

scheduledExecutorService.schedule(new Callable() {
Expand Down Expand Up @@ -116,7 +131,7 @@ public Object call() throws Exception {
return scheduledExecutorService;
}

protected void shutdownExecutorService() {
private void shutdownExecutorService() {
if (scheduledExecutorService != null) {
scheduledExecutorService.shutdown();
}
Expand Down