mirror of
https://github.com/apache/zeppelin
synced 2026-05-24 09:38:26 +00:00
Merge remote-tracking branch 'origin/master' into ZEPPELIN-2403
This commit is contained in:
commit
76a9808307
69 changed files with 355 additions and 364 deletions
33
.appveyor.yml
Normal file
33
.appveyor.yml
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
version: '1.0.0-dev.{build}'
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
build: off
|
||||
|
||||
os:
|
||||
- Visual Studio 2015
|
||||
|
||||
install:
|
||||
- echo "Install"
|
||||
|
||||
build_script:
|
||||
- echo "Build"
|
||||
|
|
@ -46,8 +46,15 @@ matrix:
|
|||
env: SCALA_VER="2.11" SPARK_VER="2.0.2" HADOOP_VER="2.6" PROFILE="-Prat" BUILD_FLAG="clean" TEST_FLAG="org.apache.rat:apache-rat-plugin:check" TEST_PROJECTS=""
|
||||
|
||||
# Test core modules
|
||||
#
|
||||
# Several tests were excluded from this configuration due to the following issues:
|
||||
# HeliumBundleFactoryTest - https://issues.apache.org/jira/browse/ZEPPELIN-2469
|
||||
# HeliumApplicationFactoryTest - https://issues.apache.org/jira/browse/ZEPPELIN-2470
|
||||
# NotebookTest - https://issues.apache.org/jira/browse/ZEPPELIN-2471
|
||||
# ZeppelinRestApiTest - https://issues.apache.org/jira/browse/ZEPPELIN-2473
|
||||
# After issues are fixed these tests need to be included back by removing them from the "-Dtests.to.exclude" property
|
||||
- jdk: "oraclejdk7"
|
||||
env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtest='!ZeppelinSparkClusterTest,!org.apache.zeppelin.spark.*' -DfailIfNoTests=false"
|
||||
env: SCALA_VER="2.11" SPARK_VER="2.1.0" HADOOP_VER="2.6" PROFILE="-Pweb-ci -Pscalding -Phelium-dev -Pexamples -Pscala-2.11" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" MODULES="-pl ${INTERPRETERS}" TEST_PROJECTS="-Dtests.to.exclude=**/ZeppelinSparkClusterTest.java,**/org.apache.zeppelin.spark.*,**/HeliumBundleFactoryTest.java,**/HeliumApplicationFactoryTest.java,**/NotebookTest.java,**/ZeppelinRestApiTest.java -DfailIfNoTests=false"
|
||||
|
||||
# Test selenium with spark module for 1.6.3
|
||||
- jdk: "oraclejdk7"
|
||||
|
|
|
|||
|
|
@ -369,4 +369,12 @@
|
|||
<description>Enable directory listings on server.</description>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
<property>
|
||||
<name>zeppelin.server.jetty.name</name>
|
||||
<value>Jetty(7.6.0.v20120127)</value>
|
||||
<description>Hardcoding Application Server name to Prevent Fingerprinting</description>
|
||||
</property>
|
||||
-->
|
||||
|
||||
</configuration>
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@
|
|||
#
|
||||
|
||||
usage() {
|
||||
echo "usage) $0 [Old version] [New version]"
|
||||
echo " ex. $0 0.7.0-SNAPSHOT 0.7.0"
|
||||
echo "usage) $0 [OLD version] [NEW version]"
|
||||
echo " ex. $0 0.8.0-SNAPSHOT 0.8.0"
|
||||
exit 1
|
||||
}
|
||||
|
||||
|
|
@ -58,6 +58,9 @@ sed -i '' 's/-'"${FROM_VERSION}"'.jar",/-'"${TO_VERSION}"'.jar",/g' zeppelin-exa
|
|||
sed -i '' 's/"version": "'"${FROM_VERSION}"'",/"version": "'"${TO_VERSION}"'",/g' zeppelin-web/src/app/tabledata/package.json
|
||||
sed -i '' 's/"version": "'"${FROM_VERSION}"'",/"version": "'"${TO_VERSION}"'",/g' zeppelin-web/src/app/visualization/package.json
|
||||
|
||||
# Change version in Dockerfile
|
||||
sed -i '' 's/Z_VERSION="'"${FROM_VERSION}"'"/Z_VERSION="'"${TO_VERSION}"'"/g' scripts/docker/zeppelin/bin/Dockerfile
|
||||
|
||||
# When preparing new dev version from release tag, doesn't need to change docs version
|
||||
if is_dev_version "${FROM_VERSION}" || ! is_dev_version "${TO_VERSION}"; then
|
||||
# When prepare new rc for the maintenance release
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@ import AngularElem._
|
|||
### Display Element
|
||||
```scala
|
||||
// automatically convert to string and print with %angular display system directive in front.
|
||||
<div><div>.display
|
||||
<div></div>.display
|
||||
```
|
||||
### Event Handler
|
||||
```scala
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ limitations under the License.
|
|||
-->
|
||||
{% include JB/setup %}
|
||||
|
||||
# Apache Zeppelin Releases Docker Images
|
||||
# Docker Image for Apache Zeppelin Releases
|
||||
|
||||
<div id="toc"></div>
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ You need to [install docker](https://docs.docker.com/engine/installation/) on yo
|
|||
### Running docker image
|
||||
|
||||
```
|
||||
docker run -p 8080:8080 --name zeppelin zeppelin:<release-version>
|
||||
docker run -p 8080:8080 --rm --name zeppelin apache/zeppelin:<release-version>
|
||||
```
|
||||
|
||||
* Zeppelin will run at `http://localhost:8080`.
|
||||
|
|
@ -42,20 +42,20 @@ docker run -p 8080:8080 --name zeppelin zeppelin:<release-version>
|
|||
If you want to specify `logs` and `notebook` dir,
|
||||
|
||||
```
|
||||
docker run -p 8080:8080 \
|
||||
docker run -p 8080:8080 --rm \
|
||||
-v $PWD/logs:/logs \
|
||||
-v $PWD/notebook:/notebook \
|
||||
-e ZEPPELIN_LOG_DIR='/logs' \
|
||||
-e ZEPPELIN_NOTEBOOK_DIR='/notebook' \
|
||||
--name zeppelin zeppelin:<release-version> # e.g '0.7.1'
|
||||
--name zeppelin apache/zeppelin:<release-version> # e.g '0.7.1'
|
||||
```
|
||||
|
||||
### Building dockerfile locally
|
||||
|
||||
```
|
||||
cd $ZEPPELIN_HOME
|
||||
cd scripts/docker/zeppelin
|
||||
cd scripts/docker/zeppelin/bin
|
||||
|
||||
./create-dockerfile.sh <release-version> # e.g '0.7.1'
|
||||
docker build -t my-zeppelin:my-tag ./
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ Congratulations, you have successfully installed Apache Zeppelin! Here are few s
|
|||
* Manage your [notebook permission](../security/notebook_authorization.html).
|
||||
* For more informations, go to **More** -> **Security** section.
|
||||
|
||||
#### Other useful informations ...
|
||||
#### Other useful information ...
|
||||
* Learn how [Display System](../displaysystem/basicdisplaysystem.html) works.
|
||||
* Use [Service Manager](#start-apache-zeppelin-with-a-service-manager) to start Zeppelin.
|
||||
* If you're using previous version please see [Upgrade Zeppelin version](./upgrade.html).
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ There are more JDBC interpreter properties you can specify like below.
|
|||
</tr>
|
||||
<tr>
|
||||
<td>zeppelin.jdbc.auth.kerberos.proxy.enable</td>
|
||||
<td>When auth type is Kerberos, enable/disable Kerberos proxy with the login user to get the connection. Default value is true.</td>
|
||||
<td>When auth type is Kerberos, enable/disable Kerberos proxy with the login user to get the connection. Default value is true.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>default.jceks.file</td>
|
||||
|
|
@ -202,7 +202,7 @@ To bind the interpreters created in the interpreter setting page, click the gear
|
|||
|
||||
<img src="../assets/themes/zeppelin/img/docs-img/click_interpreter_binding_button.png" width="600px" />
|
||||
|
||||
Select(blue) or deselect(white) the interpreter buttons depending on your use cases.
|
||||
Select(blue) or deselect(white) the interpreter buttons depending on your use cases.
|
||||
If you need to use more than one interpreter in the notebook, activate several buttons.
|
||||
Don't forget to click `Save` button, or you will face `Interpreter *** is not found` error.
|
||||
|
||||
|
|
@ -285,7 +285,7 @@ An example settings of interpreter for the two data sources, each of which has i
|
|||
</table>
|
||||
|
||||
##### Usage
|
||||
Test of execution *precode* for each data source.
|
||||
Test of execution *precode* for each data source.
|
||||
|
||||
```sql
|
||||
%jdbc
|
||||
|
|
@ -480,7 +480,7 @@ Here are some examples you can refer to. Including the below connectors, you can
|
|||
|
||||
[Maven Repository: com.amazonaws:aws-java-sdk-redshift](https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-redshift)
|
||||
|
||||
### Apache Hive
|
||||
### Apache Hive
|
||||
|
||||
<img src="../assets/themes/zeppelin/img/docs-img/hive_setting.png" width="600px" />
|
||||
|
||||
|
|
@ -507,12 +507,11 @@ Here are some examples you can refer to. Including the below connectors, you can
|
|||
<td>hive_password</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hive.proxy.user</td>
|
||||
<td>true or false</td>
|
||||
<td>default.proxy.user.property</td>
|
||||
<td>Example value: hive.server2.proxy.user</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
Connection to Hive JDBC with a proxy user can be disabled with `hive.proxy.user` property (set to true by default)
|
||||
|
||||
[Apache Hive 1 JDBC Driver Docs](https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-JDBC)
|
||||
[Apache Hive 2 JDBC Driver Docs](https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients#HiveServer2Clients-JDBC)
|
||||
|
||||
|
|
@ -534,6 +533,44 @@ Connection to Hive JDBC with a proxy user can be disabled with `hive.proxy.user`
|
|||
|
||||
[Maven Repository : org.apache.hive:hive-jdbc](https://mvnrepository.com/artifact/org.apache.hive/hive-jdbc)
|
||||
|
||||
##### Impersonation
|
||||
When Zeppelin server is running with authentication enabled, then the interpreter can utilize Hive's user proxy feature i.e. send extra parameter for creating and running a session ("hive.server2.proxy.user=": "${loggedInUser}"). This is particularly useful when multiple users are sharing a notebook.
|
||||
|
||||
To enable this set following:
|
||||
|
||||
- `zeppelin.jdbc.auth.type` as `SIMPLE` or `KERBEROS` (if required) in the interpreter setting.
|
||||
- `${prefix}.proxy.user.property` as `hive.server2.proxy.user`
|
||||
|
||||
|
||||
##### Sample configuration
|
||||
<table class="table-configuration">
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hive.driver</td>
|
||||
<td>org.apache.hive.jdbc.HiveDriver</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hive.password</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hive.url</td>
|
||||
<td>jdbc:hive2://hive-server-host:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>hive.proxy.user.property</td>
|
||||
<td>hive.server2.proxy.user</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>zeppelin.jdbc.auth.type</td>
|
||||
<td>SIMPLE</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
### Apache Phoenix
|
||||
|
||||
Phoenix supports `thick` and `thin` connection types:
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ For multi-selection, you can create a checkbox form using `${checkbox:formName=d
|
|||
|
||||
<img src="../assets/themes/zeppelin/img/screenshots/form_checkbox.png">
|
||||
|
||||
Besides, you can specify the delimiter using `${checkbox(delimiter):formName=...}`:
|
||||
You can specify the delimiter using `${checkbox(delimiter):formName=...}`:
|
||||
|
||||
<img src="../assets/themes/zeppelin/img/screenshots/form_checkbox_delimiter.png">
|
||||
|
||||
|
|
@ -84,9 +84,9 @@ Even if you uncheck this option, still you can run it by pressing `Enter`.
|
|||
|
||||
## Creates Programmatically
|
||||
|
||||
Some language backend uses programmatic way to create form. For example [ZeppelinContext](../interpreter/spark.html#zeppelincontext) provides form creation API
|
||||
Some language backends can programmatically create forms. For example [ZeppelinContext](../interpreter/spark.html#zeppelincontext) provides a form creation API
|
||||
|
||||
Here're some examples.
|
||||
Here are some examples:
|
||||
|
||||
### Text input form
|
||||
<div class="codetabs">
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ limitations under the License.
|
|||
|
||||
## Main home
|
||||
|
||||
The first time you connect to Zeppelin, you'll land at the main page similar to the below screen capture.
|
||||
The first time you connect to Zeppelin ([default installations start on http://localhost:8080](http://localhost:8080/)), you'll land at the main page similar to the below screen capture.
|
||||
|
||||
<img src="../assets/themes/zeppelin/img/ui-img/homepage.png" />
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
|
|
@ -179,10 +178,6 @@ public class JDBCInterpreter extends Interpreter {
|
|||
}
|
||||
logger.debug("JDBC PropretiesMap: {}", basePropretiesMap);
|
||||
|
||||
if (!isEmpty(property.getProperty("zeppelin.jdbc.auth.type"))) {
|
||||
JDBCSecurityImpl.createSecureConfiguration(property);
|
||||
}
|
||||
|
||||
setMaxLineResults();
|
||||
}
|
||||
|
||||
|
|
@ -355,36 +350,25 @@ public class JDBCInterpreter extends Interpreter {
|
|||
} else {
|
||||
UserGroupInformation.AuthenticationMethod authType = JDBCSecurityImpl.getAuthtype(property);
|
||||
|
||||
final String connectionUrl = appendProxyUserToURL(url, user, propertyKey);
|
||||
|
||||
JDBCSecurityImpl.createSecureConfiguration(property, authType);
|
||||
switch (authType) {
|
||||
case KERBEROS:
|
||||
if (user == null || "false".equalsIgnoreCase(
|
||||
property.getProperty("zeppelin.jdbc.auth.kerberos.proxy.enable"))) {
|
||||
connection = getConnectionFromPool(url, user, propertyKey, properties);
|
||||
property.getProperty("zeppelin.jdbc.auth.kerberos.proxy.enable"))) {
|
||||
connection = getConnectionFromPool(connectionUrl, user, propertyKey, properties);
|
||||
} else {
|
||||
if (url.trim().startsWith("jdbc:hive")) {
|
||||
StringBuilder connectionUrl = new StringBuilder(url);
|
||||
Integer lastIndexOfUrl = connectionUrl.indexOf("?");
|
||||
if (lastIndexOfUrl == -1) {
|
||||
lastIndexOfUrl = connectionUrl.length();
|
||||
}
|
||||
boolean hasProxyUser = property.containsKey("hive.proxy.user");
|
||||
if (!hasProxyUser || !property.getProperty("hive.proxy.user").equals("false")){
|
||||
logger.debug("Using hive proxy user");
|
||||
connectionUrl.insert(lastIndexOfUrl, ";hive.server2.proxy.user=" + user + ";");
|
||||
}
|
||||
connection = getConnectionFromPool(connectionUrl.toString(),
|
||||
user, propertyKey, properties);
|
||||
if (basePropretiesMap.get(propertyKey).containsKey("proxy.user.property")) {
|
||||
connection = getConnectionFromPool(connectionUrl, user, propertyKey, properties);
|
||||
} else {
|
||||
UserGroupInformation ugi = null;
|
||||
try {
|
||||
ugi = UserGroupInformation.createProxyUser(
|
||||
user, UserGroupInformation.getCurrentUser());
|
||||
user, UserGroupInformation.getCurrentUser());
|
||||
} catch (Exception e) {
|
||||
logger.error("Error in getCurrentUser", e);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(e.getMessage()).append("\n");
|
||||
stringBuilder.append(e.getCause());
|
||||
throw new InterpreterException(stringBuilder.toString());
|
||||
throw new InterpreterException("Error in getCurrentUser", e);
|
||||
}
|
||||
|
||||
final String poolKey = propertyKey;
|
||||
|
|
@ -392,28 +376,48 @@ public class JDBCInterpreter extends Interpreter {
|
|||
connection = ugi.doAs(new PrivilegedExceptionAction<Connection>() {
|
||||
@Override
|
||||
public Connection run() throws Exception {
|
||||
return getConnectionFromPool(url, user, poolKey, properties);
|
||||
return getConnectionFromPool(connectionUrl, user, poolKey, properties);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.error("Error in doAs", e);
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.append(e.getMessage()).append("\n");
|
||||
stringBuilder.append(e.getCause());
|
||||
throw new InterpreterException(stringBuilder.toString());
|
||||
throw new InterpreterException("Error in doAs", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
connection = getConnectionFromPool(url, user, propertyKey, properties);
|
||||
connection = getConnectionFromPool(connectionUrl, user, propertyKey, properties);
|
||||
}
|
||||
}
|
||||
|
||||
return connection;
|
||||
}
|
||||
|
||||
private String appendProxyUserToURL(String url, String user, String propertyKey) {
|
||||
StringBuilder connectionUrl = new StringBuilder(url);
|
||||
|
||||
if (user != null && !user.equals("anonymous") &&
|
||||
basePropretiesMap.get(propertyKey).containsKey("proxy.user.property")) {
|
||||
|
||||
Integer lastIndexOfUrl = connectionUrl.indexOf("?");
|
||||
if (lastIndexOfUrl == -1) {
|
||||
lastIndexOfUrl = connectionUrl.length();
|
||||
}
|
||||
logger.info("Using proxy user as :" + user);
|
||||
logger.info("Using proxy property for user as :" +
|
||||
basePropretiesMap.get(propertyKey).getProperty("proxy.user.property"));
|
||||
connectionUrl.insert(lastIndexOfUrl, ";" +
|
||||
basePropretiesMap.get(propertyKey).getProperty("proxy.user.property") + "=" + user + ";");
|
||||
} else if (user != null && !user.equals("anonymous") && url.contains("hive")) {
|
||||
logger.warn("User impersonation for hive has changed please refer: http://zeppelin.apache" +
|
||||
".org/docs/latest/interpreter/jdbc.html#apache-hive");
|
||||
}
|
||||
|
||||
return connectionUrl.toString();
|
||||
}
|
||||
|
||||
private String getPassword(Properties properties) throws IOException {
|
||||
if (isNotEmpty(properties.getProperty(PASSWORD_KEY))) {
|
||||
return properties.getProperty(PASSWORD_KEY);
|
||||
|
|
|
|||
|
|
@ -38,9 +38,8 @@ public class JDBCSecurityImpl {
|
|||
/***
|
||||
* @param properties
|
||||
*/
|
||||
public static void createSecureConfiguration(Properties properties) {
|
||||
AuthenticationMethod authType = getAuthtype(properties);
|
||||
|
||||
public static void createSecureConfiguration(Properties properties,
|
||||
AuthenticationMethod authType) {
|
||||
switch (authType) {
|
||||
case KERBEROS:
|
||||
Configuration conf = new
|
||||
|
|
|
|||
|
|
@ -49,7 +49,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
|
|
@ -57,9 +56,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
/**
|
||||
* Base class for livy interpreters.
|
||||
*/
|
||||
public abstract class BaseLivyInterprereter extends Interpreter {
|
||||
public abstract class BaseLivyInterpreter extends Interpreter {
|
||||
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(BaseLivyInterprereter.class);
|
||||
protected static final Logger LOGGER = LoggerFactory.getLogger(BaseLivyInterpreter.class);
|
||||
private static Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
|
||||
private static String SESSION_NOT_FOUND_PATTERN = "\"Session '\\d+' not found.\"";
|
||||
|
||||
|
|
@ -68,7 +67,6 @@ public abstract class BaseLivyInterprereter extends Interpreter {
|
|||
private int sessionCreationTimeout;
|
||||
private int pullStatusInterval;
|
||||
protected boolean displayAppInfo;
|
||||
private AtomicBoolean sessionExpired = new AtomicBoolean(false);
|
||||
protected LivyVersion livyVersion;
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
|
|
@ -77,7 +75,7 @@ public abstract class BaseLivyInterprereter extends Interpreter {
|
|||
private ConcurrentHashMap<String, Integer> paragraphId2StmtProgressMap =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
public BaseLivyInterprereter(Properties property) {
|
||||
public BaseLivyInterpreter(Properties property) {
|
||||
super(property);
|
||||
this.livyURL = property.getProperty("zeppelin.livy.url");
|
||||
this.displayAppInfo = Boolean.parseBoolean(
|
||||
|
|
@ -17,16 +17,6 @@
|
|||
|
||||
package org.apache.zeppelin.livy;
|
||||
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
import org.apache.zeppelin.scheduler.Scheduler;
|
||||
import org.apache.zeppelin.scheduler.SchedulerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import java.util.Properties;
|
|||
/**
|
||||
* Base class for PySpark Interpreter
|
||||
*/
|
||||
public abstract class LivyPySparkBaseInterpreter extends BaseLivyInterprereter {
|
||||
public abstract class LivyPySparkBaseInterpreter extends BaseLivyInterpreter {
|
||||
|
||||
public LivyPySparkBaseInterpreter(Properties property) {
|
||||
super(property);
|
||||
|
|
|
|||
|
|
@ -17,16 +17,6 @@
|
|||
|
||||
package org.apache.zeppelin.livy;
|
||||
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
import org.apache.zeppelin.scheduler.Scheduler;
|
||||
import org.apache.zeppelin.scheduler.SchedulerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,23 +17,12 @@
|
|||
|
||||
package org.apache.zeppelin.livy;
|
||||
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
import org.apache.zeppelin.scheduler.Scheduler;
|
||||
import org.apache.zeppelin.scheduler.SchedulerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Livy Spark interpreter for Zeppelin.
|
||||
*/
|
||||
public class LivySparkInterpreter extends BaseLivyInterprereter {
|
||||
public class LivySparkInterpreter extends BaseLivyInterpreter {
|
||||
|
||||
public LivySparkInterpreter(Properties property) {
|
||||
super(property);
|
||||
|
|
|
|||
|
|
@ -17,23 +17,13 @@
|
|||
|
||||
package org.apache.zeppelin.livy;
|
||||
|
||||
import org.apache.zeppelin.interpreter.*;
|
||||
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
|
||||
import org.apache.zeppelin.scheduler.Scheduler;
|
||||
import org.apache.zeppelin.scheduler.SchedulerFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
|
||||
/**
|
||||
* Livy PySpark interpreter for Zeppelin.
|
||||
*/
|
||||
public class LivySparkRInterpreter extends BaseLivyInterprereter {
|
||||
public class LivySparkRInterpreter extends BaseLivyInterpreter {
|
||||
|
||||
public LivySparkRInterpreter(Properties property) {
|
||||
super(property);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import java.util.Properties;
|
|||
/**
|
||||
* Livy SparkSQL Interpreter for Zeppelin.
|
||||
*/
|
||||
public class LivySparkSQLInterpreter extends BaseLivyInterprereter {
|
||||
public class LivySparkSQLInterpreter extends BaseLivyInterpreter {
|
||||
|
||||
public static final String ZEPPELIN_LIVY_SPARK_SQL_FIELD_TRUNCATE =
|
||||
"zeppelin.livy.spark.sql.field.truncate";
|
||||
|
|
|
|||
|
|
@ -761,7 +761,7 @@ public class LivyInterpreterIT {
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isSpark2(BaseLivyInterprereter interpreter, InterpreterContext context) {
|
||||
private boolean isSpark2(BaseLivyInterpreter interpreter, InterpreterContext context) {
|
||||
InterpreterResult result = null;
|
||||
if (interpreter instanceof LivySparkRInterpreter) {
|
||||
result = interpreter.interpret("sparkR.session()", context);
|
||||
|
|
|
|||
6
pom.xml
6
pom.xml
|
|
@ -134,6 +134,9 @@
|
|||
|
||||
<PermGen>64m</PermGen>
|
||||
<MaxPermGen>512m</MaxPermGen>
|
||||
|
||||
<!-- to be able to exclude some tests using command line -->
|
||||
<tests.to.exclude/>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
|
|
@ -555,6 +558,9 @@
|
|||
<version>${plugin.surefire.version}</version>
|
||||
<configuration combine.children="append">
|
||||
<argLine>-Xmx2g -Xms1g -Dfile.encoding=UTF-8</argLine>
|
||||
<excludes>
|
||||
<exclude>${tests.to.exclude}</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
<!-- <excludes> <exclude>**/itest/**</exclude> </excludes> <executions>
|
||||
<execution> <id>surefire-itest</id> <phase>integration-test</phase> <goals>
|
||||
|
|
|
|||
|
|
@ -1,37 +0,0 @@
|
|||
# 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.
|
||||
|
||||
FROM zeppelin:base
|
||||
MAINTAINER Apache Software Foundation <dev@zeppelin.apache.org>
|
||||
|
||||
ENV Z_VERSION="0.6.2"
|
||||
ENV LOG_TAG="[ZEPPELIN_${Z_VERSION}]:" \
|
||||
Z_HOME="/zeppelin"
|
||||
|
||||
RUN echo "$LOG_TAG Download Zeppelin binary" && \
|
||||
wget -O /tmp/zeppelin-${Z_VERSION}-bin-all.tgz http://archive.apache.org/dist/zeppelin/zeppelin-${Z_VERSION}/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
tar -zxvf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
rm -rf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
mv /zeppelin-${Z_VERSION}-bin-all ${Z_HOME}
|
||||
|
||||
RUN echo "$LOG_TAG Cleanup" && \
|
||||
apt-get autoclean && \
|
||||
apt-get clean
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR ${Z_HOME}
|
||||
CMD ["bin/zeppelin.sh"]
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# 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.
|
||||
|
||||
FROM zeppelin:base
|
||||
MAINTAINER Apache Software Foundation <dev@zeppelin.apache.org>
|
||||
|
||||
ENV Z_VERSION="0.7.0"
|
||||
ENV LOG_TAG="[ZEPPELIN_${Z_VERSION}]:" \
|
||||
Z_HOME="/zeppelin"
|
||||
|
||||
RUN echo "$LOG_TAG Download Zeppelin binary" && \
|
||||
wget -O /tmp/zeppelin-${Z_VERSION}-bin-all.tgz http://archive.apache.org/dist/zeppelin/zeppelin-${Z_VERSION}/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
tar -zxvf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
rm -rf /zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
mv /zeppelin-${Z_VERSION}-bin-all ${Z_HOME}
|
||||
|
||||
RUN echo "$LOG_TAG Cleanup" && \
|
||||
apt-get autoclean && \
|
||||
apt-get clean
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR ${Z_HOME}
|
||||
CMD ["bin/zeppelin.sh"]
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# 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.
|
||||
|
||||
FROM zeppelin:base
|
||||
MAINTAINER Apache Software Foundation <dev@zeppelin.apache.org>
|
||||
|
||||
ENV Z_VERSION="0.7.1"
|
||||
ENV LOG_TAG="[ZEPPELIN_${Z_VERSION}]:" \
|
||||
Z_HOME="/zeppelin"
|
||||
|
||||
RUN echo "$LOG_TAG Download Zeppelin binary" && \
|
||||
wget -O /tmp/zeppelin-${Z_VERSION}-bin-all.tgz http://archive.apache.org/dist/zeppelin/zeppelin-${Z_VERSION}/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
tar -zxvf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
rm -rf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
mv /zeppelin-${Z_VERSION}-bin-all ${Z_HOME}
|
||||
|
||||
RUN echo "$LOG_TAG Cleanup" && \
|
||||
apt-get autoclean && \
|
||||
apt-get clean
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR ${Z_HOME}
|
||||
CMD ["bin/zeppelin.sh"]
|
||||
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# 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.
|
||||
|
||||
FROM zeppelin:base
|
||||
MAINTAINER Apache Software Foundation <dev@zeppelin.apache.org>
|
||||
|
||||
ENV Z_VERSION="0.0.0"
|
||||
ENV LOG_TAG="[ZEPPELIN_${Z_VERSION}]:" \
|
||||
Z_HOME="/zeppelin"
|
||||
|
||||
RUN echo "$LOG_TAG Download Zeppelin binary" && \
|
||||
wget -O /tmp/zeppelin-${Z_VERSION}-bin-all.tgz http://archive.apache.org/dist/zeppelin/zeppelin-${Z_VERSION}/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
tar -zxvf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
rm -rf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
mv /zeppelin-${Z_VERSION}-bin-all ${Z_HOME}
|
||||
|
||||
RUN echo "$LOG_TAG Cleanup" && \
|
||||
apt-get autoclean && \
|
||||
apt-get clean
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
WORKDIR ${Z_HOME}
|
||||
CMD ["bin/zeppelin.sh"]
|
||||
|
||||
|
|
@ -16,7 +16,10 @@
|
|||
FROM ubuntu:16.04
|
||||
MAINTAINER Apache Software Foundation <dev@zeppelin.apache.org>
|
||||
|
||||
ENV LOG_TAG="[ZEPPELIN_BASE]:" \
|
||||
# `Z_VERSION` will be updated by `dev/change_zeppelin_version.sh`
|
||||
ENV Z_VERSION="0.8.0-SNAPSHOT"
|
||||
ENV LOG_TAG="[ZEPPELIN_${Z_VERSION}]:" \
|
||||
Z_HOME="/zeppelin" \
|
||||
LANG=en_US.UTF-8 \
|
||||
LC_ALL=en_US.UTF-8
|
||||
|
||||
|
|
@ -86,5 +89,18 @@ RUN echo "$LOG_TAG Install R related packages" && \
|
|||
R -e "install.packages('Rcpp', repos='http://cran.us.r-project.org')" && \
|
||||
Rscript -e "library('devtools'); library('Rcpp'); install_github('ramnathv/rCharts')"
|
||||
|
||||
RUN echo "$LOG_TAG Download Zeppelin binary" && \
|
||||
wget -O /tmp/zeppelin-${Z_VERSION}-bin-all.tgz http://archive.apache.org/dist/zeppelin/zeppelin-${Z_VERSION}/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
tar -zxvf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
rm -rf /tmp/zeppelin-${Z_VERSION}-bin-all.tgz && \
|
||||
mv /zeppelin-${Z_VERSION}-bin-all ${Z_HOME}
|
||||
|
||||
RUN echo "$LOG_TAG Cleanup" && \
|
||||
apt-get autoclean && \
|
||||
apt-get clean
|
||||
|
||||
EXPOSE 8080
|
||||
|
||||
ENTRYPOINT [ "/usr/bin/tini", "--" ]
|
||||
CMD [ "/bin/bash" ]
|
||||
WORKDIR ${Z_HOME}
|
||||
CMD ["bin/zeppelin.sh"]
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# 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.
|
||||
#
|
||||
|
||||
if [ $# -lt 1 ];
|
||||
then
|
||||
echo "USAGE: $0 version"
|
||||
echo "* version: 0.6.2 (released zeppelin binary version)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TAG="[CREATE-DOCKERFILE]"
|
||||
VERSION=$1
|
||||
|
||||
BASE_DIR="./base/"
|
||||
TEMPLATE_DOCKERFILE="./bin-template/Dockerfile"
|
||||
|
||||
if [ ! -d "$BASE_DIR" ]; then
|
||||
echo "${TAG} Base Directory doesn't exist: ${BASE_DIR}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TARGET_DIR="${VERSION}"
|
||||
BASE_IMAGE_TAG="base"
|
||||
|
||||
if [ ! -d "$TARGET_DIR" ]; then
|
||||
echo "${TAG} Creating Directory: ${TARGET_DIR}"
|
||||
mkdir -p ${TARGET_DIR}
|
||||
|
||||
echo "${TAG} Copying File: ${TARGET_DIR}/Dockerfile"
|
||||
cp ${TEMPLATE_DOCKERFILE} ${TARGET_DIR}/Dockerfile
|
||||
|
||||
echo "${TAG} Set Version: ${VERSION}"
|
||||
sed -i '' -e "s/Z_VERSION=\"0.0.0\"/Z_VERSION=\"${VERSION}\"/g" ${TARGET_DIR}/Dockerfile
|
||||
else
|
||||
echo "${TAG} Directory already exists: ${TARGET_DIR}"
|
||||
fi
|
||||
|
|
@ -131,10 +131,10 @@ abstract class AbstractAngularElem(val interpreterContext: InterpreterContext,
|
|||
// create AngularFunction in current paragraph
|
||||
val functionName = eventName.replaceAll("-", "_") + "_" + uniqueId
|
||||
val elem = this % Attribute(None, eventName,
|
||||
Text(s"${functionName}=$$event.timeStamp"),
|
||||
Text(s"${functionName}=${functionName} + 1"),
|
||||
Null)
|
||||
|
||||
val angularObject = addAngularObject(functionName, "")
|
||||
val angularObject = addAngularObject(functionName, 0)
|
||||
|
||||
angularObject.addWatcher(new AngularObjectWatcher(interpreterContext) {
|
||||
override def watch(oldObject: scala.Any, newObject: scala.Any, context: InterpreterContext)
|
||||
|
|
|
|||
|
|
@ -31,4 +31,8 @@ public class InterpreterException extends RuntimeException {
|
|||
super(m);
|
||||
}
|
||||
|
||||
public InterpreterException(String msg, Throwable t) {
|
||||
super(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ public class RemoteInterpreterServer
|
|||
|
||||
private void setSystemProperty(Properties properties) {
|
||||
for (Object key : properties.keySet()) {
|
||||
if (!RemoteInterpreter.isEnvString((String) key)) {
|
||||
if (!RemoteInterpreterUtils.isEnvString((String) key)) {
|
||||
String value = properties.getProperty((String) key);
|
||||
if (value == null || value.isEmpty()) {
|
||||
System.clearProperty((String) key);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package org.apache.zeppelin.interpreter.remote;
|
||||
|
||||
import org.apache.zeppelin.interpreter.InterpreterGroup;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
|
@ -73,4 +72,12 @@ public class RemoteInterpreterUtils {
|
|||
}
|
||||
return settingId;
|
||||
}
|
||||
|
||||
public static boolean isEnvString(String key) {
|
||||
if (key == null || key.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return key.matches("^[A-Z_0-9]*");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ package org.apache.zeppelin.resource;
|
|||
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.zeppelin.interpreter.InterpreterGroup;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterManagedProcess;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess;
|
||||
import org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService;
|
||||
import org.slf4j.Logger;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ package org.apache.zeppelin.scheduler;
|
|||
import org.apache.thrift.TException;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult;
|
||||
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterManagedProcess;
|
||||
import org.apache.zeppelin.interpreter.remote.RemoteInterpreterProcess;
|
||||
import org.apache.zeppelin.interpreter.thrift.RemoteInterpreterService.Client;
|
||||
import org.apache.zeppelin.scheduler.Job.Status;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
package org.apache.zeppelin.interpreter;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class DummyInterpreter extends Interpreter {
|
||||
|
||||
public DummyInterpreter(Properties property) {
|
||||
super(property);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public InterpreterResult interpret(String st, InterpreterContext context) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancel(InterpreterContext context) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public FormType getFormType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress(InterpreterContext context) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@ package org.apache.zeppelin.interpreter;
|
|||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.zeppelin.interpreter.remote.mock.MockInterpreterA;
|
||||
import org.apache.zeppelin.user.AuthenticationInfo;
|
||||
import org.junit.Test;
|
||||
|
||||
|
|
@ -31,7 +30,7 @@ public class InterpreterTest {
|
|||
public void testDefaultProperty() {
|
||||
Properties p = new Properties();
|
||||
p.put("p1", "v1");
|
||||
MockInterpreterA intp = new MockInterpreterA(p);
|
||||
Interpreter intp = new DummyInterpreter(p);
|
||||
|
||||
assertEquals(1, intp.getProperty().size());
|
||||
assertEquals("v1", intp.getProperty().get("p1"));
|
||||
|
|
@ -42,7 +41,7 @@ public class InterpreterTest {
|
|||
public void testOverriddenProperty() {
|
||||
Properties p = new Properties();
|
||||
p.put("p1", "v1");
|
||||
MockInterpreterA intp = new MockInterpreterA(p);
|
||||
Interpreter intp = new DummyInterpreter(p);
|
||||
Properties overriddenProperty = new Properties();
|
||||
overriddenProperty.put("p1", "v2");
|
||||
intp.setProperty(overriddenProperty);
|
||||
|
|
@ -74,7 +73,7 @@ public class InterpreterTest {
|
|||
Properties p = new Properties();
|
||||
p.put("p1", "replName #{noteId}, #{paragraphTitle}, #{paragraphId}, #{paragraphText}, #{replName}, #{noteId}, #{user}," +
|
||||
" #{authenticationInfo}");
|
||||
MockInterpreterA intp = new MockInterpreterA(p);
|
||||
Interpreter intp = new DummyInterpreter(p);
|
||||
intp.setUserName(user);
|
||||
String actual = intp.getProperty("p1");
|
||||
InterpreterContext.remove();
|
||||
|
|
|
|||
|
|
@ -74,7 +74,11 @@ public class LoginRestApi {
|
|||
try {
|
||||
UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
|
||||
// token.setRememberMe(true);
|
||||
|
||||
currentUser.getSession().stop();
|
||||
currentUser.getSession(true);
|
||||
currentUser.login(token);
|
||||
|
||||
HashSet<String> roles = SecurityUtils.getRoles();
|
||||
String principal = SecurityUtils.getPrincipal();
|
||||
String ticket;
|
||||
|
|
|
|||
|
|
@ -193,6 +193,9 @@ public class ZeppelinServer extends Application {
|
|||
LOG.info("Starting zeppelin server");
|
||||
try {
|
||||
jettyWebServer.start(); //Instantiates ZeppelinServer
|
||||
if (conf.getJettyName() != null) {
|
||||
org.eclipse.jetty.http.HttpGenerator.setJettyVersion(conf.getJettyName());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error while running jettyServer", e);
|
||||
System.exit(-1);
|
||||
|
|
|
|||
|
|
@ -1742,10 +1742,10 @@ public class NotebookServer extends WebSocketServlet
|
|||
}
|
||||
|
||||
private void addNewParagraphIfLastParagraphIsExecuted(Note note, Paragraph p) {
|
||||
// if it's the last paragraph and empty, let's add a new one
|
||||
// if it's the last paragraph and not empty, let's add a new one
|
||||
boolean isTheLastParagraph = note.isLastParagraph(p.getId());
|
||||
if (!(p.getText().trim().equals(p.getMagic()) ||
|
||||
Strings.isNullOrEmpty(p.getText())) &&
|
||||
if (!(Strings.isNullOrEmpty(p.getText()) ||
|
||||
p.getText().trim().equals(p.getMagic())) &&
|
||||
isTheLastParagraph) {
|
||||
Paragraph newPara = note.addNewParagraph(p.getAuthenticationInfo());
|
||||
broadcastNewParagraph(note, newPara);
|
||||
|
|
|
|||
|
|
@ -60,11 +60,13 @@ public class SecurityUtils {
|
|||
|
||||
public static Boolean isValidOrigin(String sourceHost, ZeppelinConfiguration conf)
|
||||
throws UnknownHostException, URISyntaxException {
|
||||
if (sourceHost == null || sourceHost.isEmpty()) {
|
||||
return false;
|
||||
|
||||
String sourceUriHost = "";
|
||||
|
||||
if (sourceHost != null && !sourceHost.isEmpty()) {
|
||||
sourceUriHost = new URI(sourceHost).getHost();
|
||||
sourceUriHost = (sourceUriHost == null) ? "" : sourceUriHost.toLowerCase();
|
||||
}
|
||||
String sourceUriHost = new URI(sourceHost).getHost();
|
||||
sourceUriHost = (sourceUriHost == null) ? "" : sourceUriHost.toLowerCase();
|
||||
|
||||
sourceUriHost = sourceUriHost.toLowerCase();
|
||||
String currentHost = InetAddress.getLocalHost().getHostName().toLowerCase();
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import static org.junit.Assert.assertTrue;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
|
|
@ -146,14 +147,20 @@ public class AuthenticationIT extends AbstractZeppelinIT {
|
|||
}
|
||||
}
|
||||
|
||||
private void logoutUser(String userName) {
|
||||
private void logoutUser(String userName) throws URISyntaxException {
|
||||
ZeppelinITUtils.sleep(500, false);
|
||||
driver.findElement(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
|
||||
userName + "')]")).click();
|
||||
ZeppelinITUtils.sleep(500, false);
|
||||
driver.findElement(By.xpath("//div[contains(@class, 'navbar-collapse')]//li[contains(.,'" +
|
||||
userName + "')]//a[@ng-click='navbar.logout()']")).click();
|
||||
ZeppelinITUtils.sleep(5000, false);
|
||||
ZeppelinITUtils.sleep(2000, false);
|
||||
if (driver.findElement(By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button"))
|
||||
.isDisplayed()) {
|
||||
driver.findElement(By.xpath("//*[@id='loginModal']//div[contains(@class, 'modal-header')]/button")).click();
|
||||
}
|
||||
driver.get(new URI(driver.getCurrentUrl()).resolve("/#/").toString());
|
||||
ZeppelinITUtils.sleep(500, false);
|
||||
}
|
||||
|
||||
// @Test
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ public class SecurityUtilsTest {
|
|||
new ZeppelinConfiguration(this.getClass().getResource("/zeppelin-site.xml"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullOriginWithStar() throws URISyntaxException, UnknownHostException, ConfigurationException {
|
||||
assertTrue(SecurityUtils.isValidOrigin(null,
|
||||
new ZeppelinConfiguration(this.getClass().getResource("/zeppelin-site-star.xml"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyOrigin() throws URISyntaxException, UnknownHostException, ConfigurationException {
|
||||
assertFalse(SecurityUtils.isValidOrigin("",
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ limitations under the License.
|
|||
ng-hide="viewOnly"
|
||||
ng-click="checkpointNote(note.checkpoint.message)"
|
||||
style="margin-left: 4px;"
|
||||
tooltip-append-to-body="true"
|
||||
tooltip-class="revisionTooltip"
|
||||
tooltip-placement="bottom" uib-tooltip="Commit this note">Commit
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -483,20 +483,23 @@ function NotebookCtrl ($scope, $route, $routeParams, $location, $rootScope,
|
|||
}
|
||||
|
||||
$scope.$on('addParagraph', function (event, paragraph, index) {
|
||||
if ($scope.paragraphUrl) {
|
||||
if ($scope.paragraphUrl || $scope.revisionView === true) {
|
||||
return
|
||||
}
|
||||
addPara(paragraph, index)
|
||||
})
|
||||
|
||||
$scope.$on('removeParagraph', function (event, paragraphId) {
|
||||
if ($scope.paragraphUrl) {
|
||||
if ($scope.paragraphUrl || $scope.revisionView === true) {
|
||||
return
|
||||
}
|
||||
removePara(paragraphId)
|
||||
})
|
||||
|
||||
$scope.$on('moveParagraph', function (event, paragraphId, newIdx) {
|
||||
if ($scope.revisionView === true) {
|
||||
return
|
||||
}
|
||||
let removedPara = removePara(paragraphId)
|
||||
if (removedPara && removedPara.length === 1) {
|
||||
addPara(removedPara[0], newIdx)
|
||||
|
|
@ -958,6 +961,9 @@ function NotebookCtrl ($scope, $route, $routeParams, $location, $rootScope,
|
|||
})
|
||||
|
||||
$scope.$on('insertParagraph', function (event, paragraphId, position) {
|
||||
if ($scope.revisionView === true) {
|
||||
return
|
||||
}
|
||||
let newIndex = -1
|
||||
for (let i = 0; i < $scope.note.paragraphs.length; i++) {
|
||||
if ($scope.note.paragraphs[i].id === paragraphId) {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,10 @@
|
|||
border-color: #ccc;
|
||||
}
|
||||
|
||||
.revisionTooltip {
|
||||
z-index: 10003;
|
||||
}
|
||||
|
||||
.caretSeparator {
|
||||
height: 22px;
|
||||
line-height: 9px;
|
||||
|
|
@ -313,7 +317,6 @@
|
|||
max-width: 50%;
|
||||
}
|
||||
|
||||
|
||||
.inactivelink {
|
||||
color: darkgrey;
|
||||
cursor: default;
|
||||
|
|
@ -330,4 +333,3 @@
|
|||
}
|
||||
.noteAction.headroom--unpinned { top: -100px; }
|
||||
.noteAction.headroom--pinned { top: 50px; /** `noteAction` top */ }
|
||||
|
||||
|
|
|
|||
|
|
@ -610,7 +610,9 @@ function ParagraphCtrl ($scope, $rootScope, $route, $window, $routeParams, $loca
|
|||
let session = editor.getSession()
|
||||
let dirtyText = session.getValue()
|
||||
$scope.dirtyText = dirtyText
|
||||
$scope.startSaveTimer()
|
||||
if ($scope.dirtyText !== $scope.originalText) {
|
||||
$scope.startSaveTimer()
|
||||
}
|
||||
setParagraphMode(session, dirtyText, editor.getCursorPosition())
|
||||
}
|
||||
|
||||
|
|
@ -629,9 +631,18 @@ function ParagraphCtrl ($scope, $rootScope, $route, $window, $routeParams, $loca
|
|||
$scope.editor.getSession().setUseWrapMode(true)
|
||||
$scope.editor.setTheme('ace/theme/chrome')
|
||||
$scope.editor.setReadOnly($scope.isRunning($scope.paragraph))
|
||||
|
||||
if ($scope.paragraphFocused) {
|
||||
let prefix = '%' + getInterpreterName($scope.paragraph.text)
|
||||
let paragraphText = $scope.paragraph.text ? $scope.paragraph.text.trim() : ''
|
||||
|
||||
$scope.editor.focus()
|
||||
$scope.goToEnd($scope.editor)
|
||||
if (prefix === paragraphText) {
|
||||
$timeout(function () {
|
||||
$scope.editor.gotoLine(2, 0)
|
||||
}, 0)
|
||||
}
|
||||
}
|
||||
|
||||
autoAdjustEditorHeight(_editor)
|
||||
|
|
@ -839,14 +850,16 @@ function ParagraphCtrl ($scope, $rootScope, $route, $window, $routeParams, $loca
|
|||
|
||||
let getEditorSetting = function (paragraph, interpreterName) {
|
||||
let deferred = $q.defer()
|
||||
websocketMsgSrv.getEditorSetting(paragraph.id, interpreterName)
|
||||
$timeout(
|
||||
$scope.$on('editorSetting', function (event, data) {
|
||||
if (paragraph.id === data.paragraphId) {
|
||||
deferred.resolve(data)
|
||||
if (!$scope.revisionView) {
|
||||
websocketMsgSrv.getEditorSetting(paragraph.id, interpreterName)
|
||||
$timeout(
|
||||
$scope.$on('editorSetting', function (event, data) {
|
||||
if (paragraph.id === data.paragraphId) {
|
||||
deferred.resolve(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
), 1000)
|
||||
}
|
||||
return deferred.promise
|
||||
}
|
||||
|
||||
|
|
@ -1241,23 +1254,28 @@ function ParagraphCtrl ($scope, $rootScope, $route, $window, $routeParams, $loca
|
|||
}
|
||||
|
||||
$scope.updateParagraph = function (oldPara, newPara, updateCallback) {
|
||||
// 1. get status, refreshed
|
||||
// 1. can't update on revision view
|
||||
if ($scope.revisionView === true) {
|
||||
return
|
||||
}
|
||||
|
||||
// 2. get status, refreshed
|
||||
const statusChanged = (newPara.status !== oldPara.status)
|
||||
const resultRefreshed = (newPara.dateFinished !== oldPara.dateFinished) ||
|
||||
isEmpty(newPara.results) !== isEmpty(oldPara.results) ||
|
||||
newPara.status === ParagraphStatus.ERROR ||
|
||||
(newPara.status === ParagraphStatus.FINISHED && statusChanged)
|
||||
|
||||
// 2. update texts managed by $scope
|
||||
// 3. update texts managed by $scope
|
||||
$scope.updateAllScopeTexts(oldPara, newPara)
|
||||
|
||||
// 3. execute callback to update result
|
||||
// 4. execute callback to update result
|
||||
updateCallback()
|
||||
|
||||
// 4. update remaining paragraph objects
|
||||
// 5. update remaining paragraph objects
|
||||
$scope.updateParagraphObjectWhenUpdated(newPara)
|
||||
|
||||
// 5. handle scroll down by key properly if new paragraph is added
|
||||
// 6. handle scroll down by key properly if new paragraph is added
|
||||
if (statusChanged || resultRefreshed) {
|
||||
// when last paragraph runs, zeppelin automatically appends new paragraph.
|
||||
// this broadcast will focus to the newly inserted paragraph
|
||||
|
|
|
|||
|
|
@ -498,6 +498,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
return getString(ConfVars.ZEPPELIN_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE);
|
||||
}
|
||||
|
||||
public String getJettyName() {
|
||||
return getString(ConfVars.ZEPPELIN_SERVER_JETTY_NAME);
|
||||
}
|
||||
|
||||
public Map<String, String> dumpConfigurations(ZeppelinConfiguration conf,
|
||||
ConfigurationKeyPredicate predicate) {
|
||||
Map<String, String> configurations = new HashMap<>();
|
||||
|
|
@ -646,7 +650,8 @@ public class ZeppelinConfiguration extends XMLConfiguration {
|
|||
ZEPPELIN_ANONYMOUS_ALLOWED("zeppelin.anonymous.allowed", true),
|
||||
ZEPPELIN_CREDENTIALS_PERSIST("zeppelin.credentials.persist", true),
|
||||
ZEPPELIN_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE("zeppelin.websocket.max.text.message.size", "1024000"),
|
||||
ZEPPELIN_SERVER_DEFAULT_DIR_ALLOWED("zeppelin.server.default.dir.allowed", false);
|
||||
ZEPPELIN_SERVER_DEFAULT_DIR_ALLOWED("zeppelin.server.default.dir.allowed", false),
|
||||
ZEPPELIN_SERVER_JETTY_NAME("zeppelin.server.jetty.name", null);
|
||||
|
||||
private String varName;
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
|
|
|||
|
|
@ -246,8 +246,13 @@ public class InterpreterSettingManager {
|
|||
if (!Files.exists(interpreterBindingPath)) {
|
||||
Files.createFile(interpreterBindingPath);
|
||||
|
||||
Set<PosixFilePermission> permissions = EnumSet.of(OWNER_READ, OWNER_WRITE);
|
||||
Files.setPosixFilePermissions(interpreterBindingPath, permissions);
|
||||
try {
|
||||
Set<PosixFilePermission> permissions = EnumSet.of(OWNER_READ, OWNER_WRITE);
|
||||
Files.setPosixFilePermissions(interpreterBindingPath, permissions);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// File system does not support Posix file permissions (likely windows) - continue anyway.
|
||||
logger.warn("unable to setPosixFilePermissions on '{}'.", interpreterBindingPath);
|
||||
};
|
||||
}
|
||||
|
||||
FileOutputStream fos = new FileOutputStream(interpreterBindingPath.toFile(), false);
|
||||
|
|
|
|||
|
|
@ -142,21 +142,13 @@ public class RemoteInterpreter extends Interpreter {
|
|||
private Map<String, String> getEnvFromInterpreterProperty(Properties property) {
|
||||
Map<String, String> env = new HashMap<>();
|
||||
for (Object key : property.keySet()) {
|
||||
if (isEnvString((String) key)) {
|
||||
if (RemoteInterpreterUtils.isEnvString((String) key)) {
|
||||
env.put((String) key, property.getProperty((String) key));
|
||||
}
|
||||
}
|
||||
return env;
|
||||
}
|
||||
|
||||
static boolean isEnvString(String key) {
|
||||
if (key == null || key.length() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return key.matches("^[A-Z_0-9]*");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClassName() {
|
||||
return className;
|
||||
|
|
@ -353,7 +353,6 @@ public class Note implements Serializable, ParagraphJobListener {
|
|||
private Paragraph createParagraph(int index, AuthenticationInfo authenticationInfo) {
|
||||
Paragraph p = new Paragraph(this, this, factory, interpreterSettingManager);
|
||||
p.setAuthenticationInfo(authenticationInfo);
|
||||
p.addUser(p, p.getUser());
|
||||
setParagraphMagic(p, index);
|
||||
return p;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ module.exports = {
|
|||
{ test: /\.eot(\?\S*)?$/, loader: 'url-loader', }, {
|
||||
test: /\.ttf(\?\S*)?$/, loader: 'url-loader', }, {
|
||||
test: /\.svg(\?\S*)?$/, loader: 'url-loader', }, {
|
||||
test: /\.png(\?\S*)?$/, loader: 'url-loader', }, {
|
||||
test: /\.jpg(\?\S*)?$/, loader: 'url-loader', }, {
|
||||
test: /\.json$/, loader: 'json-loader' }, ],
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -854,13 +854,13 @@ public class RemoteInterpreterTest {
|
|||
|
||||
@Test
|
||||
public void testEnvStringPattern() {
|
||||
assertFalse(RemoteInterpreter.isEnvString(null));
|
||||
assertFalse(RemoteInterpreter.isEnvString(""));
|
||||
assertFalse(RemoteInterpreter.isEnvString("abcDEF"));
|
||||
assertFalse(RemoteInterpreter.isEnvString("ABC-DEF"));
|
||||
assertTrue(RemoteInterpreter.isEnvString("ABCDEF"));
|
||||
assertTrue(RemoteInterpreter.isEnvString("ABC_DEF"));
|
||||
assertTrue(RemoteInterpreter.isEnvString("ABC_DEF123"));
|
||||
assertFalse(RemoteInterpreterUtils.isEnvString(null));
|
||||
assertFalse(RemoteInterpreterUtils.isEnvString(""));
|
||||
assertFalse(RemoteInterpreterUtils.isEnvString("abcDEF"));
|
||||
assertFalse(RemoteInterpreterUtils.isEnvString("ABC-DEF"));
|
||||
assertTrue(RemoteInterpreterUtils.isEnvString("ABCDEF"));
|
||||
assertTrue(RemoteInterpreterUtils.isEnvString("ABC_DEF"));
|
||||
assertTrue(RemoteInterpreterUtils.isEnvString("ABC_DEF123"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -217,4 +217,20 @@ public class NoteTest {
|
|||
|
||||
assertEquals("getName should return same as getId when name is empty", note.getId(), note.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void personalizedModeReturnDifferentParagraphInstancePerUser() {
|
||||
Note note = new Note(repo, interpreterFactory, interpreterSettingManager, jobListenerFactory, index, credentials, noteEventListener);
|
||||
|
||||
String user1 = "user1";
|
||||
String user2 = "user2";
|
||||
note.setPersonalizedMode(true);
|
||||
note.addNewParagraph(new AuthenticationInfo(user1));
|
||||
Paragraph baseParagraph = note.getParagraphs().get(0);
|
||||
Paragraph user1Paragraph = baseParagraph.getUserParagraph(user1);
|
||||
Paragraph user2Paragraph = baseParagraph.getUserParagraph(user2);
|
||||
assertNotEquals(System.identityHashCode(baseParagraph), System.identityHashCode(user1Paragraph));
|
||||
assertNotEquals(System.identityHashCode(baseParagraph), System.identityHashCode(user2Paragraph));
|
||||
assertNotEquals(System.identityHashCode(user1Paragraph), System.identityHashCode(user2Paragraph));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue