merge with master

This commit is contained in:
astroshim 2015-11-30 17:40:58 +09:00
commit cb993914c4
74 changed files with 2015 additions and 654 deletions

View file

@ -22,17 +22,17 @@ before_install:
- "sh -e /etc/init.d/xvfb start"
install:
- mvn package -DskipTests -Phadoop-2.3 -Ppyspark -B
- mvn package -DskipTests -Pspark-1.5 -Phadoop-2.3 -Ppyspark -B
before_script:
-
script:
# spark 1.5
- mvn package -Pbuild-distr -Phadoop-2.3 -Ppyspark -B
- mvn package -Pbuild-distr -Pspark-1.5 -Phadoop-2.3 -Ppyspark -B
- ./testing/startSparkCluster.sh 1.5.2 2.3
- echo "export SPARK_HOME=`pwd`/spark-1.5.2-bin-hadoop2.3" > conf/zeppelin-env.sh
- mvn verify -Pusing-packaged-distr -Phadoop-2.3 -Ppyspark -B
- mvn verify -Pusing-packaged-distr -Pspark-1.5 -Phadoop-2.3 -Ppyspark -B
- ./testing/stopSparkCluster.sh 1.5.2 2.3
# spark 1.4
- rm -rf `pwd`/interpreter/spark

172
README.md
View file

@ -49,133 +49,109 @@ _Notes:_
If you want to build Zeppelin from the source, please first clone this repository, then:
```
mvn clean package -DskipTests
mvn clean package -DskipTests [Options]
```
To build with a specific Spark version, Hadoop version or specific features, define one or more of the `spark`, `pyspark`, `hadoop` and `yarn` profiles, such as:
Each Interpreter requires different Options.
#### Spark Interpreter
To build with a specific Spark version, Hadoop version or specific features, define one or more of the following profiles and options:
##### -Pspark-[version]
Set spark major version
Available profiles are
```
-Pspark-1.5 [Version to run in local spark mode]
-Ppyspark [optional: enable PYTHON support in spark via the %pyspark interpreter]
-Pyarn [optional: enable YARN support]
-Dhadoop.version=2.2.0 [hadoop distribution]
-Phadoop-2.2 [hadoop version]
-Pspark-1.5
-Pspark-1.4
-Pspark-1.3
-Pspark-1.2
-Pspark-1.1
-Pcassandra-spark-1.5
-Pcassandra-spark-1.4
-Pcassandra-spark-1.3
-Pcassandra-spark-1.2
-Pcassandra-spark-1.1
```
Currently, final/full distributions run with:
minor version can be adjusted by `-Dspark.version=x.x.x`
##### -Phadoop-[version]
set hadoop major version
Available profiles are
```
mvn clean package -Pspark-1.5 -Phadoop-2.4 -Pyarn -Ppyspark
-Phadoop-0.23
-Phadoop-1
-Phadoop-2.2
-Phadoop-2.3
-Phadoop-2.4
-Phadoop-2.6
```
Spark 1.5.x
minor version can be adjusted by `-Dhadoop.version=x.x.x`
```
mvn clean package -Pspark-1.5 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
```
Spark 1.4.x
##### -Pyarn (optional)
```
mvn clean package -Pspark-1.4 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
```
Spark 1.3.x
enable YARN support for local mode
```
mvn clean package -Pspark-1.3 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
```
Spark 1.2.x
```
mvn clean package -Pspark-1.2 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
```
Spark 1.1.x
##### -Ppyspark (optional)
```
mvn clean package -Pspark-1.1 -Dhadoop.version=2.2.0 -Phadoop-2.2 -DskipTests
```
CDH 5.X
enable PySpark support for local mode
##### -Pvendor-repo (optional)
enable 3rd party vendor repository (cloudera)
##### -Pmapr[version] (optional)
```
mvn clean package -Pspark-1.2 -Dhadoop.version=2.5.0-cdh5.3.0 -Phadoop-2.4 -DskipTests
```
For the MapR Hadoop Distribution, these profiles will handle the Hadoop version. As MapR allows different versions
of Spark to be installed, you should specify which version of Spark is installed on the cluster by adding a Spark profile (-Pspark-1.2, -Pspark-1.3, etc.) as needed. For Hive, check the hive/pom.xml and adjust the version installed as well. The correct Maven
artifacts can be found for every version of MapR at http://doc.mapr.com
MapR 3.x
```
mvn clean package -Pmapr3 -DskipTests
```
MapR 4.0.x
```
mvn clean package -Pmapr40 -DskipTests
```
MapR 4.1
```
mvn clean package -Pmapr41 -DskipTests
```
MapR 5.0
```
mvn clean package -Pmapr50 -DskipTests
```
Yarn (Hadoop 2.7.x)
Available profiles are
```
mvn clean package -Pspark-1.4 -Dspark.version=1.4.1 -Dhadoop.version=2.7.0 -Phadoop-2.6 -Pyarn -DskipTests
```
Yarn (Hadoop 2.6.x)
```
mvn clean package -Pspark-1.1 -Dhadoop.version=2.6.0 -Phadoop-2.6 -Pyarn -DskipTests
```
Yarn (Hadoop 2.4.x)
```
mvn clean package -Pspark-1.1 -Dhadoop.version=2.4.0 -Phadoop-2.4 -Pyarn -DskipTests
```
Yarn (Hadoop 2.3.x)
```
mvn clean package -Pspark-1.1 -Dhadoop.version=2.3.0 -Phadoop-2.3 -Pyarn -DskipTests
```
Yarn (Hadoop 2.2.x)
```
mvn clean package -Pspark-1.1 -Dhadoop.version=2.2.0 -Phadoop-2.2 -Pyarn -DskipTests
-Pmapr3
-Pmapr40
-Pmapr41
-Pmapr50
```
Ignite (1.1.0-incubating and later)
Here're some examples:
```
# basic build
mvn clean package -Pspark-1.5 -Phadoop-2.4 -Pyarn -Ppyspark
# spark-cassandra integration
mvn clean package -Pcassandra-spark-1.5 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
# with CDH
mvn clean package -Pspark-1.2 -Dhadoop.version=2.5.0-cdh5.3.0 -Phadoop-2.4 -Pvendor-repo -DskipTests
# with MapR
mvn clean package -Pspark-1.5 -Pmapr50 -DskipTests
```
#### Ignite Interpreter
```
mvn clean package -Dignite.version=1.1.0-incubating -DskipTests
```
Spark-Cassandra integration (Spark 1.1.x)
```
mvn clean package -Pcassandra-spark-1.1 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
```
Spark-Cassandra integration (Spark 1.2.x)
```
mvn clean package -Pcassandra-spark-1.2 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
```
Spark-Cassandra integration (Spark 1.3.x)
```
mvn clean package -Pcassandra-spark-1.3 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
```
Spark-Cassandra integration (Spark 1.4.x)
```
mvn clean package -Pcassandra-spark-1.4 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
```
Spark-Cassandra integration (Spark 1.5.x)
```
mvn clean package -Pcassandra-spark-1.5 -Dhadoop.version=2.6.0 -Phadoop-2.6 -DskipTests
```
### Configure
If you wish to configure Zeppelin option (like port number), configure the following files:

View file

@ -76,8 +76,6 @@ function addJarInDir(){
fi
}
export ZEPPELIN_CLASSPATH
# Text encoding for
# read/write job into files,
# receiving/displaying query/result.

View file

@ -31,6 +31,12 @@
<description>Server port.</description>
</property>
<property>
<name>zeppelin.server.context.path</name>
<value>/</value>
<description>Context Path of the Web Application</description>
</property>
<property>
<name>zeppelin.notebook.dir</name>
<value>notebook</value>

View file

@ -3,7 +3,7 @@
This readme will walk you through building the Zeppelin documentation, which is included here with the Zeppelin source code.
## Build website
## Build documentation
See https://help.github.com/articles/using-jekyll-with-pages#installing-jekyll
**tl;dr version:**
@ -36,3 +36,12 @@ See https://help.github.com/articles/using-jekyll-with-pages#installing-jekyll
## Adding a new page
rake page name="new-page.md"
## Bumping up version
* `BASE_PATH` property in _config.yml
* `ZEPPELIN <small>([VERSION])</small>` in _includes/themes/zeppelin/_navigation.html
need to be updated

View file

@ -55,7 +55,7 @@ JB :
# - Only the following values are falsy: ["", null, false]
# - When setting BASE_PATH it must be a valid url.
# This means always setting the protocol (http|https) or prefixing with "/"
BASE_PATH : false
BASE_PATH : /docs/0.6.0-incubating-SNAPSHOT
# By default, the asset_path is automatically defined relative to BASE_PATH plus the enabled theme.
# ex: [BASE_PATH]/assets/themes/[THEME-NAME]

View file

@ -1,4 +1,4 @@
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div id="menu" class="navbar navbar-inverse navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
@ -7,21 +7,75 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="/">
<a class="navbar-brand" href="{{BASE_PATH}}">
<img src="/assets/themes/zeppelin/img/zeppelin_logo.png" width="50" alt="I'm zeppelin">
Zeppelin <small>(0.6.0-incubating-SNAPSHOT)</small>
<span style="vertical-align:middle">Zeppelin</span>
<span style="vertical-align:baseline"><small>(0.6.0-incubating-SNAPSHOT)</small></span>
</a>
</div>
<nav class="navbar-collapse collapse" role="navigation">
<ul class="nav navbar-nav">
{% assign pages_list = site.pages %}
{% assign group = 'nav-left' %}
{% include JB/pages_list %}
</ul>
<ul class="nav navbar-nav navbar-right">
{% assign pages_list = site.pages %}
{% assign group = 'nav-right' %}
{% include JB/pages_list %}
<li>
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Quick Start <b class="caret"></b></a>
<ul class="dropdown-menu">
<!-- li><span><b>Overview</b><span></li -->
<li><a href="{{BASE_PATH}}/index.html">Overview</a></li>
<li role="separator" class="divider"></li>
<!-- li><span><b>Install</b><span></li -->
<li><a href="{{BASE_PATH}}/install/install.html">Install</a></li>
<li><a href="{{BASE_PATH}}/install/yarn_install.html">YARN Install</a></li>
<li role="separator" class="divider"></li>
<!-- li><span><b>Tutorial</b><span></li -->
<li><a href="{{BASE_PATH}}/tutorial/tutorial.html">Tutorial</a></li>
<li role="separator" class="divider"></li>
<!-- li><span><b>Guide</b><span></li -->
<li><a href="{{BASE_PATH}}/manual/dynamicform.html">Dynamic Form</a></li>
</ul>
</li>
<li>
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Interpreter <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="{{BASE_PATH}}/interpreter/cassandra.html">Cassandra</a></li>
<li><a href="{{BASE_PATH}}/interpreter/flink.html">Flink</a></li>
<li><a href="{{BASE_PATH}}/interpreter/geode.html">Geode</a></li>
<li><a href="{{BASE_PATH}}/pleasecontribute.html">Hive</a></li>
<li><a href="{{BASE_PATH}}/interpreter/ignite.html">Ignite</a></li>
<li><a href="{{BASE_PATH}}/interpreter/lens.html">Lens</a></li>
<li><a href="{{BASE_PATH}}/interpreter/markdown.html">Markdown</a></li>
<li><a href="{{BASE_PATH}}/interpreter/postgresql.html">Postgresql, hawq</a></li>
<li><a href="{{BASE_PATH}}/pleasecontribute.html">Shell</a></li>
<li><a href="{{BASE_PATH}}/interpreter/spark.html">Spark</a></li>
<li><a href="{{BASE_PATH}}/pleasecontribute.html">Tajo</a></li>
</ul>
</li>
<li>
<a href="#" data-toggle="dropdown" class="dropdown-toggle">Display System <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="{{BASE_PATH}}/displaysystem/display.html">Text</a></li>
<li><a href="{{BASE_PATH}}/displaysystem/display.html#html">Html</a></li>
<li><a href="{{BASE_PATH}}/displaysystem/table.html">Table</a></li>
<li><a href="{{BASE_PATH}}/displaysystem/angular.html">Angular</a></li>
</ul>
</li>
<li>
<a href="#" data-toggle="dropdown" class="dropdown-toggle">More <b class="caret"></b></a>
<ul class="dropdown-menu">
<!-- li><span><b>Manual</b><span></li -->
<li><a href="{{BASE_PATH}}/manual/notebookashomepage.html">Notebook as Homepage</a></li>
<li role="separator" class="divider"></li>
<!-- li><span><b>Notebook Storage</b><span></li -->
<li><a href="{{BASE_PATH}}/storage/storage.html">S3 Storage</a></li>
<li role="separator" class="divider"></li>
<!-- li><span><b>REST API</b><span></li -->
<li><a href="{{BASE_PATH}}/rest-api/rest-interpreter.html">Interpreter API</a></li>
<li><a href="{{BASE_PATH}}/rest-api/rest-notebook.html">Notebook API</a></li>
<li role="separator" class="divider"></li>
<!-- li><span><b>Development</b><span></li -->
<li><a href="{{BASE_PATH}}/development/writingzeppelininterpreter.html">Writing Zeppelin Interpreter</a></li>
<li><a href="{{BASE_PATH}}/development/howtocontribute.html">How to contribute (code)</a></li>
<li><a href="{{BASE_PATH}}/development/howtocontributewebsite.html">How to contribute (website)</a></li>
</ul>
</li>
</ul>
</nav><!--/.navbar-collapse -->
</div>

View file

@ -7,47 +7,57 @@ body {
}
.jumbotron {
background-color: #3071a9;
background: #3071a9;
}
.navbar-brand {
padding: 12px 12px;
padding-top: 15px;
padding-top: 10px;
padding-bottom: 10px;
}
.navbar {
background-color:#3071a9;
border-bottom:0px;
height: 50px;
background: #3071a9;
border-bottom: 0px;
height: 50px;
}
.navbar-inverse .navbar-nav > li > a {
color: #ffffff;
background-color:#3071a9;
color: white;
background: #3071a9;
}
.navbar-inverse .navbar-nav > li > a:hover,
.navbar-inverse .navbar-nav > li > a:hover,
.navbar-inverse .navbar-nav > li > a:focus {
color: #ffffff;
background-color: #2C6094;
color: white !important;
background: #2C6094 !important;
}
.navbar-inverse .navbar-nav > li > a.active:hover,
.navbar-inverse .navbar-collapse.in .navbar-nav .dropdown-menu > li > a:hover,
.navbar-inverse .navbar-collapse.in .navbar-nav .dropdown-menu > li > a:focus {
color: white !important;
background: #2C6094 !important;
}
.navbar-inverse .navbar-collapse.in .navbar-nav .dropdown-menu > li > a {
color: white !important;
}
.navbar-inverse .navbar-collapse.in .navbar-nav .divider {
background: #286090;
}
.navbar-inverse .navbar-nav > li > a.active:hover,
.navbar-inverse .navbar-nav > li > a.active:focus {
text-decoration: none;
background-color: #265380;
background: #265380;
}
.navbar-inverse .navbar-nav > li > a.active {
background-color: #265380;
}
.navbar-inverse .navbar-brand:hover,
.navbar-inverse .navbar-brand:focus {
background: #265380;
}
.navbar-inverse .navbar-brand {
color: #fff;
color: white;
text-decoration: none;
font-size: 32px;
}
@ -55,12 +65,12 @@ body {
.navbar-inverse .navbar-collapse,
.navbar-inverse .navbar-form {
border-color: #265380;
background-color: #3071a9;
background: #3071a9;
}
@media (max-width: 768px) {
.navbar-collapse.in {
box-shadow: 0px 2px 5px 0px rgba(0, 0, 0, 0.4);
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.4);
}
.bigFingerButton {
@ -72,7 +82,7 @@ body {
}
.bigFingerButton {
margin-right: 10px;
margin-right: 10px;
}
.navbar-inverse .navbar-toggle {
@ -82,14 +92,13 @@ body {
.navbar-inverse .navbar-toggle:hover,
.navbar-inverse .navbar-toggle:focus {
border-color: #265380;
background-color: #265380;
background: #265380;
}
.navbar-inverse .navbar-toggle:focus {
outline-width: 0px;
outline-width: 0;
}
/* CUSTOMIZE THE CAROUSEL
-------------------------------------------------- */
@ -107,6 +116,7 @@ body {
.carousel .item {
height: 300px;
}
.carousel-control {
background-image: none !important;
}
@ -118,10 +128,12 @@ body {
min-width: 100%;
height: 300px;
}
.carousel-indicators {
margin-top:30px;
margin-bottom:0px;
margin-top: 30px;
margin-bottom: 0;
}
@media screen and (min-width: 768px) {
.carousel-indicators {
margin-bottom: -60px;
@ -131,145 +143,273 @@ body {
}
}
.jumbotron h1,
.jumbotron p {
color: #fff;
color: white;
}
.jumbotron .thumbnail {
margin-top: 0;
}
.jumbotron.small {
padding: 0 0 0 0;
color : #ffffff;
padding: 0 0 0 0;
color: white;
}
.jumbotron.small .title{
float : left;
font-weight : bold;
font-size : 20px;
height : 30px;
margin-right: 20px;
float: left;
font-weight: bold;
font-size: 20px;
height: 30px;
margin-right: 20px;
}
.jumbotron.small .subtitle{
font-size : 14px;
height : 30px;
vertical-align:text-bottom;
padding-top:7px;
font-size: 14px;
height: 30px;
vertical-align:text-bottom;
padding-top:7px;
}
.jumbotron.small .description{
margin-top: 7px;
margin-top: 7px;
}
/* screenshot img inside of doc */
.screenshot {
width : 800px;
width: 800px;
}
/* Table on the index page */
.table-container {
position: absolute;
position: absolute;
}
.table-stack {
/* border: 1px solid #6371a9;*/
width:200px; padding: 5px 5px 5px 5px;
width: 200px;
padding: 5px;
}
.table-stack table {
width:100%
width: 100%;
}
.table-stack tr td{
border: 1px solid #FFFFFF;
height : 40px;
background-color : #6371a9;
color : #FFFFFF;
border: 1px solid white;
height: 40px;
background: #6371a9;
color: white;
}
.table-stack .gray {
background-color:#DDDDDD;
color:#777777;
background:#DDDDDD;
color:#777777;
}
/* Table for property */
.table-configuration {
width : 800px;
<<<<<<< HEAD
width : 100%;
border : 1px solid gray;
=======
width: 800px;
border: 1px solid gray;
>>>>>>> PR_TOOL_MERGE_PR_483
}
.table-configuration tr td {
border : 1px solid gray;
padding : 5px 5px 5px 5px;
border: 1px solid gray;
padding: 5px;
}
.table-configuration tr th {
border : 1px solid gray;
padding : 5px 5px 5px 5px;
background-color: #B0C4DE;
border: 1px solid gray;
padding: 5px;
background: #B0C4DE;
}
.rotate270 {
width:15px;padding:10px 0px 0px 0px;
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
width: 15px;
padding: 10px 0 0 0;
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
}
/* Custom container */
<<<<<<< HEAD
/* <a> */
.container a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0;
}
/* <hn> */
.container h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }
.container h1 {
font-size: 30px;
color: black; }
.container h2 {
font-size: 28px;
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 1px solid #E5E5E5;}
.container h3 {
font-size: 22px;
padding-top: 5px;
padding-bottom: 5px;
border-bottom: 1px solid #E5E5E5;}
.container h4 {
font-size: 18px; }
.container h5 {
font-size: 14px; }
.container h6 {
font-size: 14px;
color: #777777;}
/* <li, ul, ol> */
.container li {
margin: 0; }
.container li p.first {
display: inline-block;}
.container ul :first-child, ol :first-child {
margin-top: 0;
}
/* <table> */
.container table {
width : 100%;
padding: 0;
border-collapse: collapse; }
.container table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }
.container table tr th {
text-align: center;
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }
.container table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px;
}
/* <code> */
.container code{
color:#000000;
font-size: 90%;
font-family: "Menlo", "Lucida Console", monospace;
background-color: #f8f8f8;
border: 1px solid #cccccc;
}
/* <pre> */
.container pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;}
.container pre code {
font-size: 95%;
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}
/* <blockquote> */
.container blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
.container blockquote > :first-child {
margin-top: 0; }
.container blockquote > :last-child {
margin-bottom: 0; }
.container blockquote p{
font-size: 14px;
}
/* <p>, <blockquote>, <table>, <pre>, <img> margin */
.container p, blockquote, table, pre, img {
margin: 12px 0;
}
=======
>>>>>>> PR_TOOL_MERGE_PR_483
.container-narrow {
margin: 0 auto;
/* max-width: 960px; */
}
.container-narrow > hr {
margin: 30px 0; }
margin: 30px 0;
}
/* posts index */
.post > h3.title {
position: relative;
padding-top: 10px; }
padding-top: 10px;
}
.post > h3.title span.date {
position: absolute;
right: 0;
font-size: 0.9em; }
font-size: 0.9em;
}
.post > .more {
margin: 10px 0;
text-align: left; }
text-align: left;
}
/* post-full*/
.post-full .date {
margin-bottom: 20px;
font-weight: bold; }
font-weight: bold;
}
/* tag_box */
.tag_box {
list-style: none;
margin: 0;
overflow: hidden; }
overflow: hidden;
}
.tag_box li {
line-height: 28px; }
line-height: 28px;
}
.tag_box li i {
opacity: 0.9; }
opacity: 0.9;
}
.tag_box.inline li {
float: left; }
float: left;
}
.tag_box a {
padding: 3px 6px;
@ -278,76 +418,105 @@ body {
color: #555;
border-radius: 3px;
text-decoration: none;
border: 1px dashed #cccccc; }
border: 1px dashed #cccccc;
}
.tag_box a span {
vertical-align: super;
font-size: 0.8em; }
font-size: 0.8em;
}
.tag_box a:hover {
background-color: #e5e5e5; }
background: #e5e5e5;
}
.tag_box a.active {
background: #57A957;
border: 1px solid #4c964d;
color: #FFF; }
color: white;
}
.jumbotron h1 {
font-family: 'Patua One', cursive; }
font-family: 'Patua One', cursive;
}
.jumbotron small {
font-size: 60%;
color: #FFF;}
font-size: 60%;
color: white;
}
.navbar-brand {
font-family: 'Patua One', cursive;
font-family: 'Patua One', cursive;
}
.navbar-brand small {
font-size: 14px;
font-family: 'Helvetica Neue', Helvetica;
color: #FFF; }
font-size: 14px;
font-family: 'Helvetica Neue', Helvetica;
color: white;
}
.navbar-collapse.collapse {
max-height: 50px;}
max-height: 50px;
}
#apache .caret {
margin-left: 4px;
border-top-color: #FFF;
margin-left: 4px;
border-top-color: white;
}
.navbar-inverse .navbar-nav > .open > a,
.navbar-inverse .navbar-nav > .open > a:hover,
.navbar-inverse .navbar-nav > .open > a:focus {
color: #ffffff;
background-color: #286090;
color: white;
background: #286090;
}
/* Custom, iPhone Retina */
@media only screen and (max-width : 480px) {
/* Custom, iPhone Retina */
@media only screen and (max-width: 480px) {
.jumbotron h1 {
display: none;
}
.navbar-brand small {
display: none;
color: #FFF;
display: none;
color: white;
}
}
@media only screen and (max-width : 768px) {
@media only screen and (max-width: 768px) {
.navbar .navbar-brand {
padding-bottom: 0;
padding-bottom: 0;
}
}
@media only screen
and (min-width : 768px)
and (max-width : 1024px) {
and (min-width: 768px)
and (max-width: 1024px) {
.navbar-brand small {
display: none;
display: none;
}
.navbar-collapse.collapse {
padding-right: 0;
padding-right: 0;
}
}
/* docs dropdown menu */
#menu .dropdown-menu li span {
padding: 3px 10px 10px 10px;
font-size: 13px;
}
#menu .caret {
border-top-color: white;
border-bottom-color: white;
}
#menu .open .caret {
border-top-color: #428bca;
border-bottom-color: #428bca;
}
#menu .navbar-brand {
margin-right: 50px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -25,7 +25,7 @@ Zeppelin Interpreter is a language backend. For example to use scala code in Zep
Every Interpreter belongs to an InterpreterGroup. InterpreterGroup is a unit of start/stop interpreter.
Interpreters in the same InterpreterGroup can reference each other. For example, SparkSqlInterpreter can reference SparkInterpreter to get SparkContext from it while they're in the same group.
<img class="img-responsive" style="width:50%; border: 1px solid #ecf0f1;" height="auto" src="../../assets/themes/zeppelin/img/interpreter.png" />
<img class="img-responsive" style="width:50%; border: 1px solid #ecf0f1;" height="auto" src="/assets/themes/zeppelin/img/interpreter.png" />
All Interpreters in the same interpreter group are launched in a single, separate JVM process. The Interpreter communicates with Zeppelin engine via thrift.

View file

@ -32,7 +32,7 @@ Therefore, you can not only update scope variable from your interpreter but also
#### Print AngularJS view
To use angular display system, your output should starts with "%angular".
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular.png" width=600px />
<img src="/assets/themes/zeppelin/img/screenshots/display_angular.png" width=600px />
Note that display system is backend independent.
@ -62,7 +62,7 @@ z.angularUnbindGlobal(String name)
In the example, let's bind "world" variable 'name'. Then you can see AngularJs view are updated immediately.
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular1.png" width=600px />
<img src="/assets/themes/zeppelin/img/screenshots/display_angular1.png" width=600px />
<br />
@ -91,8 +91,8 @@ z.angularUnwatchGlobal(String name)
Let's make an button, that increment 'run' variable by 1 when it is clicked.
z.angularBind("run", 0) will initialize 'run' to zero. And then register watcher of 'run'.
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular2.png" width=600px />
<img src="/assets/themes/zeppelin/img/screenshots/display_angular2.png" width=600px />
After clicked button, you'll see both 'run' and numWatched are increased by 1
<img src="../../assets/themes/zeppelin/img/screenshots/display_angular3.png" width=600px />
<img src="/assets/themes/zeppelin/img/screenshots/display_angular3.png" width=600px />

View file

@ -27,11 +27,11 @@ limitations under the License.
Zeppelin prints output of language backend in text, by default.
<img src="../../assets/themes/zeppelin/img/screenshots/display_text.png" />
<img src="/assets/themes/zeppelin/img/screenshots/display_text.png" />
You can explicitly say you're using text display system.
<img src="../../assets/themes/zeppelin/img/screenshots/display_text1.png" />
<img src="/assets/themes/zeppelin/img/screenshots/display_text1.png" />
Note that display system is backend independent.
@ -42,4 +42,4 @@ Note that display system is backend independent.
With '%html' directive, Zeppelin treats your output as html
<img src="../../assets/themes/zeppelin/img/screenshots/display_html.png" />
<img src="/assets/themes/zeppelin/img/screenshots/display_html.png" />

View file

@ -24,14 +24,14 @@ limitations under the License.
If you have data that row seprated by '\n' (newline) and column separated by '\t' (tab) with first row as header row, for example
<img src="../../assets/themes/zeppelin/img/screenshots/display_table.png" />
<img src="/assets/themes/zeppelin/img/screenshots/display_table.png" />
You can simply use %table display system to leverage Zeppelin's built in visualization.
<img src="../../assets/themes/zeppelin/img/screenshots/display_table1.png" />
<img src="/assets/themes/zeppelin/img/screenshots/display_table1.png" />
Note that display system is backend independent.
If table contents start with %html, it is interpreted as an HTML.
<img src="../../assets/themes/zeppelin/img/screenshots/display_table_html.png" />
<img src="/assets/themes/zeppelin/img/screenshots/display_table_html.png" />

View file

@ -35,14 +35,14 @@ limitations under the License.
* [cassandra](./interpreter/cassandra.html)
* [flink](./interpreter/flink.html)
* [geode](./interpreter/geode.html)
* [hive](../pleasecontribute.html)
* [hive](./pleasecontribute.html)
* [ignite](./interpreter/ignite.html)
* [lens](./interpreter/lens.html)
* [md](../pleasecontribute.html)
* [md](./interpreter/markdown.html)
* [postgresql, hawq](./interpreter/postgresql.html)
* [sh](../pleasecontribute.html)
* [sh](./pleasecontribute.html)
* [spark](./interpreter/spark.html)
* [tajo](../pleasecontribute.html)
* [tajo](./pleasecontribute.html)
### Storage
* [S3 Storage](./storage/storage.html)

View file

@ -34,7 +34,7 @@ limitations under the License.
</ul>
</div>
<div class="col-md-7"><img class="img-responsive" style="border: 1px solid #ecf0f1;" height="auto" src="assets/themes/zeppelin/img/notebook.png" /></div>
<div class="col-md-7"><img class="img-responsive" style="border: 1px solid #ecf0f1;" height="auto" src="/assets/themes/zeppelin/img/notebook.png" /></div>
</div>
@ -44,17 +44,16 @@ limitations under the License.
Zeppelin interpreter concept allows any language/data-processing-backend to be plugged into Zeppelin.
Currently Zeppelin supports many interpreters such as Scala(with Apache Spark), Python(with Apache Spark), SparkSQL, Hive, Markdown and Shell.
<img class="img-responsive" src="assets/themes/zeppelin/img/screenshots/multiple_language_backend.png" />
<img class="img-responsive" src="/assets/themes/zeppelin/img/screenshots/multiple_language_backend.png" />
Adding new language-backend is really simple. Learn [how to write a zeppelin interpreter](./development/writingzeppelininterpreter.html).
<br />
### Apache Spark integration
Zeppelin provides built-in Apache Spark integration. You don't need to build a separate module, plugin or library for it.
<img src="assets/themes/zeppelin/img/spark_logo.jpg" width="80px" />
<img src="/assets/themes/zeppelin/img/spark_logo.jpg" width="80px" />
Zeppelin's Spark integration provides
@ -69,10 +68,10 @@ Some basic charts are already included in Zeppelin. Visualizations are not limit
<div class="row">
<div class="col-md-6">
<img class="img-responsive" src="./assets/themes/zeppelin/img/graph1.png" />
<img class="img-responsive" src="/assets/themes/zeppelin/img/graph1.png" />
</div>
<div class="col-md-6">
<img class="img-responsive" src="./assets/themes/zeppelin/img/graph2.png" />
<img class="img-responsive" src="/assets/themes/zeppelin/img/graph2.png" />
</div>
</div>
@ -82,7 +81,7 @@ With simple drag and drop Zeppelin aggeregates the values and display them in pi
<div class="row">
<div class="col-md-8">
<img class="img-responsive" src="./assets/themes/zeppelin/img/screenshots/pivot.png" />
<img class="img-responsive" src="/assets/themes/zeppelin/img/screenshots/pivot.png" />
</div>
</div>
Learn more about Zeppelin's Display system. ( [text](./displaysystem/display.html), [html](./displaysystem/display.html#html), [table](./displaysystem/table.html), [angular](./displaysystem/angular.html) )
@ -93,7 +92,7 @@ Learn more about Zeppelin's Display system. ( [text](./displaysystem/display.htm
Zeppelin can dynamically create some input forms into your notebook.
<img class="img-responsive" src="./assets/themes/zeppelin/img/screenshots/form_input.png" />
<img class="img-responsive" src="/assets/themes/zeppelin/img/screenshots/form_input.png" />
Learn more about [Dynamic Forms](./manual/dynamicform.html).
@ -103,7 +102,7 @@ Learn more about [Dynamic Forms](./manual/dynamicform.html).
Notebook URL can be shared among collaborators. Zeppelin can then broadcast any changes in realtime, just like the collaboration in Google docs.
<img src="./assets/themes/zeppelin/img/screenshots/collaboration.png" />
<img src="/assets/themes/zeppelin/img/screenshots/collaboration.png" />
<br />
### Publish
@ -112,7 +111,7 @@ Notebook URL can be shared among collaborators. Zeppelin can then broadcast any
This way, you can easily embed it as an iframe inside of your website.</p>
<div class="row">
<img class="img-responsive center-block" src="./assets/themes/zeppelin/img/screenshots/publish.png" />
<img class="img-responsive center-block" src="/assets/themes/zeppelin/img/screenshots/publish.png" />
</div>
<br />

View file

@ -21,46 +21,14 @@ limitations under the License.
## Build
## From binary package
#### Prerequisites
Download latest binary package from [Download](../download.html).
* Java 1.7
* None root account
* Apache Maven
Build tested on OSX, CentOS 6.
Checkout source code from [https://github.com/apache/incubator-zeppelin](https://github.com/apache/incubator-zeppelin)
#### Local mode
```
mvn install -DskipTests
```
#### Cluster mode
```
mvn install -DskipTests -Dspark.version=1.1.0 -Dhadoop.version=2.2.0
```
Change spark.version and hadoop.version to your cluster's one.
#### Custom built Spark
Note that is you uses custom build spark, you need build Zeppelin with custome built spark artifact. To do that, deploy spark artifact to local maven repository using
```
sbt/sbt publish-local
```
and then build Zeppelin with your custom built Spark
```
mvn install -DskipTests -Dspark.version=1.1.0-Custom -Dhadoop.version=2.2.0
```
## Build from source
Check instructions in [README](https://github.com/apache/incubator-zeppelin/blob/master/README.md) to build from source.
@ -80,19 +48,141 @@ Configuration can be done by both environment variable(conf/zeppelin-env.sh) and
<td>ZEPPELIN_PORT</td>
<td>zeppelin.server.port</td>
<td>8080</td>
<td>Zeppelin server port. Note that port+1 is used for web socket</td>
<td>Zeppelin server port.</td>
</tr>
<tr>
<td>ZEPPELIN_MEM</td>
<td>N/A</td>
<td>-Xmx1024m -XX:MaxPermSize=512m</td>
<td>JVM mem options</td>
</tr>
<tr>
<td>ZEPPELIN_INTP_MEM</td>
<td>N/A</td>
<td>ZEPPELIN_MEM</td>
<td>JVM mem options for interpreter process</td>
</tr>
<tr>
<td>ZEPPELIN_JAVA_OPTS</td>
<td>N/A</td>
<td></td>
<td>JVM Options</td>
</tr>
<tr>
<td>ZEPPELIN_ALLOWED_ORIGINS</td>
<td>zeppelin.server.allowed.origins</td>
<td>*</td>
<td>Allows a way to specify a ',' separated list of allowed origins for rest and websockets. i.e. http://localhost:8080</td>
</tr>
<tr>
<td>ZEPPELIN_SERVER_CONTEXT_PATH</td>
<td>zeppelin.server.context.path</td>
<td>/</td>
<td>Context Path of the Web Application</td>
</tr>
<tr>
<td>ZEPPELIN_SSL</td>
<td>zeppelin.ssl</td>
<td>false</td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_CLIENT_AUTH</td>
<td>zeppelin.ssl.client.auth</td>
<td>false</td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_KEYSTORE_PATH</td>
<td>zeppelin.ssl.keystore.path</td>
<td>keystore</td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_KEYSTORE_TYPE</td>
<td>zeppelin.ssl.keystore.type</td>
<td>JKS</td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_KEYSTORE_PASSWORD</td>
<td>zeppelin.ssl.keystore.password</td>
<td></td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_KEY_MANAGER_PASSWORD</td>
<td>zeppelin.ssl.key.manager.password</td>
<td></td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_TRUSTSTORE_PATH</td>
<td>zeppelin.ssl.truststore.path</td>
<td></td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_TRUSTSTORE_TYPE</td>
<td>zeppelin.ssl.truststore.type</td>
<td></td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_SSL_TRUSTSTORE_PASSWORD</td>
<td>zeppelin.ssl.truststore.password</td>
<td></td>
<td></td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_HOMESCREEN</td>
<td>zeppelin.notebook.homescreen</td>
<td></td>
<td>Id of notebook to be displayed in homescreen ex) 2A94M5J1Z</td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_HOMESCREEN_HIDE</td>
<td>zeppelin.notebook.homescreen.hide</td>
<td>false</td>
<td>hide homescreen notebook from list when this value set to "true"</td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_DIR</td>
<td>zeppelin.notebook.dir</td>
<td>notebook</td>
<td>Where notebook file is saved</td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_S3_BUCKET</td>
<td>zeppelin.notebook.s3.bucket</td>
<td>zeppelin</td>
<td>Bucket where notebook saved</td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_S3_USER</td>
<td>zeppelin.notebook.s3.user</td>
<td>user</td>
<td>User in bucket where notebook saved. For example bucket/user/notebook/2A94M5J1Z/note.json</td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_STORAGE</td>
<td>zeppelin.notebook.storage</td>
<td>org.apache.zeppelin.notebook.repo.VFSNotebookRepo</td>
<td>Comma separated list of notebook storage</td>
</tr>
<tr>
<td>ZEPPELIN_NOTEBOOK_RELOAD_FROM_STORAGE</td>
<td>zeppelin.notebook.reloadAllNotesFromStorage</td>
<td>false</td>
<td>Notebook list and contents will be always loaded from repository if set true. If set false, modified notebooks or new notebooks added on file system level won't be reflected on Zeppelin till user restarts Zeppelin.</td>
</tr>
<tr>
<td>ZEPPELIN_INTERPRETERS</td>
<td>zeppelin.interpreters</td>
<description></description>
<td>org.apache.zeppelin.spark.SparkInterpreter,<br />org.apache.zeppelin.spark.PySparkInterpreter,<br />org.apache.zeppelin.spark.SparkSqlInterpreter,<br />org.apache.zeppelin.spark.DepInterpreter,<br />org.apache.zeppelin.markdown.Markdown,<br />org.apache.zeppelin.shell.ShellInterpreter,<br />org.apache.zeppelin.hive.HiveInterpreter</td>
<td>org.apache.zeppelin.spark.SparkInterpreter,<br />org.apache.zeppelin.spark.PySparkInterpreter,<br />org.apache.zeppelin.spark.SparkSqlInterpreter,<br />org.apache.zeppelin.spark.DepInterpreter,<br />org.apache.zeppelin.markdown.Markdown,<br />org.apache.zeppelin.shell.ShellInterpreter,<br />org.apache.zeppelin.hive.HiveInterpreter<br />
...
</td>
<td>Comma separated interpreter configurations [Class]. First interpreter become a default</td>
</tr>
<tr>
@ -101,19 +191,14 @@ Configuration can be done by both environment variable(conf/zeppelin-env.sh) and
<td>interpreter</td>
<td>Zeppelin interpreter directory</td>
</tr>
<tr>
<td>MASTER</td>
<td></td>
<td>N/A</td>
<td>Spark master url. eg. spark://master_addr:7077. Leave empty if you want to use local mode</td>
</tr>
<tr>
<td>ZEPPELIN_JAVA_OPTS</td>
<td></td>
<td>N/A</td>
<td>JVM Options</td>
</table>
<br />
You'll also need to configure individual interpreter. Information can be found in 'Interpreter' section in this documentation.
For example [Spark](../interpreter/spark.html).
<br />
## Start/Stop
#### Start Zeppelin
@ -121,7 +206,6 @@ Configuration can be done by both environment variable(conf/zeppelin-env.sh) and
bin/zeppelin-daemon.sh start
```
After successful start, visit http://localhost:8080 with your web browser.
Note that port **8081** also need to be accessible for websocket connection.
#### Stop Zeppelin

View file

@ -30,9 +30,9 @@ group: manual
In a notebook, to enable the **Cassandra** interpreter, click on the **Gear** icon and select **Cassandra**
<center>
![Interpreter Binding](/assets/themes/zeppelin/img/docs-img/cassandra-InterpreterBinding.png)
![Interpreter Selection](/assets/themes/zeppelin/img/docs-img/cassandra-InterpreterSelection.png)
![Interpreter Binding](../assets/themes/zeppelin/img/docs-img/cassandra-InterpreterBinding.png)
![Interpreter Selection](../assets/themes/zeppelin/img/docs-img/cassandra-InterpreterSelection.png)
</center>
<hr/>
@ -44,7 +44,7 @@ group: manual
To access the interactive help, type **HELP;**
<center>
![Interactive Help](/assets/themes/zeppelin/img/docs-img/cassandra-InteractiveHelp.png)
![Interactive Help](../assets/themes/zeppelin/img/docs-img/cassandra-InteractiveHelp.png)
</center>
<hr/>
@ -283,7 +283,7 @@ There is a drop-down menu on the top left corner to expand objects details. On t
<br/>
<center>
![Describe Schema](/assets/themes/zeppelin/img/docs-img/cassandra-DescribeSchema.png)
![Describe Schema](../assets/themes/zeppelin/img/docs-img/cassandra-DescribeSchema.png)
</center>
<hr/>
@ -551,7 +551,7 @@ For this, first go to the **Interpreter** menu and click on the **Create** butto
<br/>
<br/>
<center>
![Create Interpreter](/assets/themes/zeppelin/img/docs-img/cassandra-NewInterpreterInstance.png)
![Create Interpreter](../assets/themes/zeppelin/img/docs-img/cassandra-NewInterpreterInstance.png)
</center>
In the interpreter creation form, put **cass-instance2** as **Name** and select the **cassandra**
@ -559,7 +559,7 @@ in the interpreter drop-down list
<br/>
<br/>
<center>
![Interpreter Name](/assets/themes/zeppelin/img/docs-img/cassandra-InterpreterName.png)
![Interpreter Name](../assets/themes/zeppelin/img/docs-img/cassandra-InterpreterName.png)
</center>
Click on **Save** to create the new interpreter instance. Now you should be able to see it in the interpreter list.
@ -567,7 +567,7 @@ in the interpreter drop-down list
<br/>
<br/>
<center>
![Interpreter In List](/assets/themes/zeppelin/img/docs-img/cassandra-NewInterpreterInList.png)
![Interpreter In List](../assets/themes/zeppelin/img/docs-img/cassandra-NewInterpreterInList.png)
</center>
Go back to your notebook and click on the **Gear** icon to configure interpreter bindings.
@ -577,7 +577,7 @@ interpreter list instead of the standard **cassandra** instance.
<br/>
<br/>
<center>
![Interpreter Instance Selection](/assets/themes/zeppelin/img/docs-img/cassandra-InterpreterInstanceSelection.png)
![Interpreter Instance Selection](../assets/themes/zeppelin/img/docs-img/cassandra-InterpreterInstanceSelection.png)
</center>
<hr/>

View file

@ -37,23 +37,23 @@ This interpreter supports the [Geode](http://geode.incubator.apache.org/) [Objec
This [Video Tutorial](https://www.youtube.com/watch?v=zvzzA9GXu3Q) illustrates some of the features provided by the `Geode Interpreter`.
### Create Interpreter
### Create Interpreter
By default Zeppelin creates one `Geode/OQL` instance. You can remove it or create more instances.
By default Zeppelin creates one `Geode/OQL` instance. You can remove it or create more instances.
Multiple Geode instances can be created, each configured to the same or different backend Geode cluster. But over time a `Notebook` can have only one Geode interpreter instance `bound`. That means you _can not_ connect to different Geode clusters in the same `Notebook`. This is a known Zeppelin limitation.
Multiple Geode instances can be created, each configured to the same or different backend Geode cluster. But over time a `Notebook` can have only one Geode interpreter instance `bound`. That means you _cannot_ connect to different Geode clusters in the same `Notebook`. This is a known Zeppelin limitation.
To create new Geode instance open the `Interprter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `geode`. Then follow the configuration instructions and `Save` the new instance.
To create new Geode instance open the `Interpreter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `geode`. Then follow the configuration instructions and `Save` the new instance.
> Note: The `Name` of the instance is used only to distinct the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%geode.oql` tag.
> Note: The `Name` of the instance is used only to distinguish the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%geode.oql` tag.
### Bind to Notebook
In the `Notebook` click on the `settings` icon in the top right corner. The select/deselect the interpreters to be bound with the `Notebook`.
### Configuration
You can modify the configuration of the Geode from the `Interpreter` section. The Geode interpreter express the following properties:
You can modify the configuration of the Geode from the `Interpreter` section. The Geode interpreter expresses the following properties:
<table class="table-configuration">
<tr>
<th>Property Name</th>
@ -76,16 +76,16 @@ You can modify the configuration of the Geode from the `Interpreter` section. T
<td>1000</td>
</tr>
</table>
### How to use
> *Tip 1: Use (CTRL + .) for OQL auto-completion.*
> *Tip 2: Alawys start the paragraphs with the full `%geode.oql` prefix tag! The short notation: `%geode` would still be able run the OQL queries but the syntax highlighting and the auto-completions will be disabled.*
> *Tip 2: Always start the paragraphs with the full `%geode.oql` prefix tag! The short notation: `%geode` would still be able run the OQL queries but the syntax highlighting and the auto-completions will be disabled.*
#### Create / Destroy Regions
The OQL sepecification does not support [Geode Regions](https://cwiki.apache.org/confluence/display/GEODE/Index#Index-MainConceptsandComponents) mutation operations. To `creaate`/`destroy` regions one should use the [GFSH](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/chapter_overview.html) shell tool instead. To wokr this it assumes that the GFSH is colocated with Zeppelin server.
The OQL specification does not support [Geode Regions](https://cwiki.apache.org/confluence/display/GEODE/Index#Index-MainConceptsandComponents) mutation operations. To `create`/`destroy` regions one should use the [GFSH](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/chapter_overview.html) shell tool instead. In the following it is assumed that the GFSH is colocated with Zeppelin server.
```bash
%sh
@ -98,26 +98,26 @@ gfsh << EOF
destroy region --name=/regionCompany
create region --name=regionEmployee --type=REPLICATE
create region --name=regionCompany --type=REPLICATE
exit;
EOF
```
Above snippet re-creates two regions: `regionEmployee` and `regionCompany`. Note that you have to explicetely specify the locator host and port. The values should match those you have used in the Geode Interpreter configuration. Comprehensive list of [GFSH Commands by Functional Area](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/gfsh_quick_reference.html).
Above snippet re-creates two regions: `regionEmployee` and `regionCompany`. Note that you have to explicitly specify the locator host and port. The values should match those you have used in the Geode Interpreter configuration. Comprehensive list of [GFSH Commands by Functional Area](http://geode-docs.cfapps.io/docs/tools_modules/gfsh/gfsh_quick_reference.html).
#### Basic OQL
```sql
%geode.oql
SELECT count(*) FROM /regionEmploee
```sql
%geode.oql
SELECT count(*) FROM /regionEmployee
```
OQL `IN` and `SET` filters:
```sql
%geode.oql
SELECT * FROM /regionEmployee
SELECT * FROM /regionEmployee
WHERE companyId IN SET(2) OR lastName IN SET('Tzolov13', 'Tzolov73')
```
@ -126,15 +126,15 @@ OQL `JOIN` operations
```sql
%geode.oql
SELECT e.employeeId, e.firstName, e.lastName, c.id as companyId, c.companyName, c.address
FROM /regionEmployee e, /regionCompany c
FROM /regionEmployee e, /regionCompany c
WHERE e.companyId = c.id
```
By default the QOL responses contain only the region entry values. To access the keys, query the `EntrySet` instead:
By default the QOL responses contain only the region entry values. To access the keys, query the `EntrySet` instead:
```sql
%geode.oql
SELECT e.key, e.value.companyId, e.value.email
SELECT e.key, e.value.companyId, e.value.email
FROM /regionEmployee.entrySet e
```
Following query will return the EntrySet value as a Blob:
@ -160,7 +160,7 @@ gfsh -e "connect" -e "list members"
#### Apply Zeppelin Dynamic Forms
You can leverage [Zepplein Dynamic Form](https://zeppelin.incubator.apache.org/docs/manual/dynamicform.html) inside your OQL queries. You can use both the `text input` and `select form` parametrization features
You can leverage [Zeppelin Dynamic Form](../manual/dynamicform.html) inside your OQL queries. You can use both the `text input` and `select form` parameterization features
```sql
%geode.oql
@ -197,7 +197,5 @@ http-service-port=8484
start-dev-rest-api=true
```
### Auto-completion
The Geode Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggesntions in a pop-up window.
### Auto-completion
The Geode Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggestions in a pop-up window.

View file

@ -11,7 +11,7 @@ group: manual
### Overview
[Apache Ignite](https://ignite.apache.org/) In-Memory Data Fabric is a high-performance, integrated and distributed in-memory platform for computing and transacting on large-scale data sets in real-time, orders of magnitude faster than possible with traditional disk-based or flash technologies.
![Apache Ignite](/assets/themes/zeppelin/img/docs-img/ignite-logo.png)
![Apache Ignite](../assets/themes/zeppelin/img/docs-img/ignite-logo.png)
You can use Zeppelin to retrieve distributed data from cache using Ignite SQL interpreter. Moreover, Ignite interpreter allows you to execute any Scala code in cases when SQL doesn't fit to your requirements. For example, you can populate data into your caches or execute distributed computations.
@ -68,12 +68,12 @@ At the "Interpreters" menu, you may edit Ignite interpreter or create new one. Z
</tr>
</table>
![Configuration of Ignite Interpreter](/assets/themes/zeppelin/img/docs-img/ignite-interpreter-setting.png)
![Configuration of Ignite Interpreter](../assets/themes/zeppelin/img/docs-img/ignite-interpreter-setting.png)
### Interpreter Binding for Zeppelin Notebook
After configuring Ignite interpreter, create your own notebook. Then you can bind interpreters like below image.
![Binding Interpreters](/assets/themes/zeppelin/img/docs-img/ignite-interpreter-binding.png)
![Binding Interpreters](../assets/themes/zeppelin/img/docs-img/ignite-interpreter-binding.png)
For more interpreter binding information see [here](http://zeppelin.incubator.apache.org/docs/manual/interpreters.html).
@ -87,7 +87,7 @@ For example, you can select top 10 words in the words cache using the following
select _val, count(_val) as cnt from String group by _val order by cnt desc limit 10
```
![IgniteSql on Zeppelin](/assets/themes/zeppelin/img/docs-img/ignite-sql-example.png)
![IgniteSql on Zeppelin](../assets/themes/zeppelin/img/docs-img/ignite-sql-example.png)
As long as your Ignite version and Zeppelin Ignite version is same, you can also use scala code. Please check the Zeppelin Ignite version before you download your own Ignite.
@ -109,7 +109,7 @@ As long as your Ignite version and Zeppelin Ignite version is same, you can also
collectionAsScalaIterable(res).foreach(println _)
```
![Using Scala Code](/assets/themes/zeppelin/img/docs-img/ignite-scala-example.png)
![Using Scala Code](../assets/themes/zeppelin/img/docs-img/ignite-scala-example.png)
Apache Ignite also provides a guide docs for Zeppelin ["Ignite with Apache Zeppelin"](https://apacheignite.readme.io/docs/data-analysis-with-apache-zeppelin)

View file

@ -11,7 +11,7 @@ group: manual
### Overview
[Apache Lens](https://lens.apache.org/) provides an Unified Analytics interface. Lens aims to cut the Data Analytics silos by providing a single view of data across multiple tiered data stores and optimal execution environment for the analytical query. It seamlessly integrates Hadoop with traditional data warehouses to appear like one.
![Apache Lens](/assets/themes/zeppelin/img/docs-img/lens-logo.png)
![Apache Lens](../assets/themes/zeppelin/img/docs-img/lens-logo.png)
### Installing and Running Lens
In order to use Lens interpreters, you may install Apache Lens in some simple steps:
@ -75,11 +75,11 @@ At the "Interpreters" menu, you can to edit Lens interpreter or create new one.
</tr>
</table>
![Apache Lens Interpreter Setting](/assets/themes/zeppelin/img/docs-img/lens-interpreter-setting.png)
![Apache Lens Interpreter Setting](../assets/themes/zeppelin/img/docs-img/lens-interpreter-setting.png)
### Interpreter Bindging for Zeppelin Notebook
After configuring Lens interpreter, create your own notebook, then you can bind interpreters like below image.
![Zeppelin Notebook Interpreter Biding](/assets/themes/zeppelin/img/docs-img/lens-interpreter-binding.png)
![Zeppelin Notebook Interpreter Biding](../assets/themes/zeppelin/img/docs-img/lens-interpreter-binding.png)
For more interpreter binding information see [here](http://zeppelin.incubator.apache.org/docs/manual/interpreters.html).
@ -159,14 +159,14 @@ As you can see in this video, they are using Lens Client Shell(./bin/lens-cli.sh
```
![Lens Query Result](/assets/themes/zeppelin/img/docs-img/lens-result.png)
![Lens Query Result](../assets/themes/zeppelin/img/docs-img/lens-result.png)
These are just examples that provided in advance by Lens. If you want to explore whole tutorials of Lens, see the [tutorial video](https://cwiki.apache.org/confluence/display/LENS/2015/07/13/20+Minute+video+demo+of+Apache+Lens+through+examples).
### Lens UI Service
Lens also provides web UI service. Once the server starts up, you can open the service on http://serverhost:19999/index.html and browse. You may also check the structure that you made and use query easily here.
![Lens UI Servive](/assets/themes/zeppelin/img/docs-img/lens-ui-service.png)
![Lens UI Servive](../assets/themes/zeppelin/img/docs-img/lens-ui-service.png)

View file

@ -0,0 +1,22 @@
---
layout: page
title: "Markdown Interpreter"
description: "Markdown Interpreter"
group: manual
---
{% include JB/setup %}
## Markdown Interpreter for Apache Zeppelin
### Overview
[Markdown](http://daringfireball.net/projects/markdown/) is a plain text formatting syntax designed so that it can be converted to HTML.
Zeppelin uses markdown4j, for more examples and extension support checkout [markdown4j](https://code.google.com/p/markdown4j/)
In Zeppelin notebook you can use ``` %md ``` in the beginning of a paragraph to invoke the Markdown interpreter to generate static html from Markdown plain text.
In Zeppelin, Markdown interpreter is enabled by default.
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/markdown-interpreter-setting.png" width="600px" />
### Example
The following example demonstrates the basic usage of Markdown in a Zeppelin notebook.
<img src="{{BASE_PATH}}/assets/themes/zeppelin/img/docs-img/markdown-example.png" width="800px" />

View file

@ -19,7 +19,7 @@ group: manual
<tr>
<td>%psql.sql</td>
<td>PostgreSqlInterpreter</td>
<td>Provides SQL environment for Postgresql, HAWQ and Greenplum</td>
<td>Provides SQL environment for PostgreSQL, HAWQ and Greenplum</td>
</tr>
</table>
@ -28,22 +28,22 @@ group: manual
This interpreter seamlessly supports the following SQL data processing engines:
* [PostgreSQL](http://www.postgresql.org/) - OSS, Object-relational database management system (ORDBMS)
* [Apache HAWQ](http://pivotal.io/big-data/pivotal-hawq) - Powerful [Open Source](https://wiki.apache.org/incubator/HAWQProposal) SQL-On-Hadoop engine.
* [PostgreSQL](http://www.postgresql.org/) - OSS, Object-relational database management system (ORDBMS)
* [Apache HAWQ](http://pivotal.io/big-data/pivotal-hawq) - Powerful [Open Source](https://wiki.apache.org/incubator/HAWQProposal) SQL-On-Hadoop engine.
* [Greenplum](http://pivotal.io/big-data/pivotal-greenplum-database) - MPP database built on open source PostgreSQL.
This [Video Tutorial](https://www.youtube.com/watch?v=wqXXQhJ5Uk8) illustrates some of the features provided by the `Postgresql Interpreter`.
### Create Interpreter
### Create Interpreter
By default Zeppelin creates one `PSQL` instance. You can remove it or create new instances.
By default Zeppelin creates one `PSQL` instance. You can remove it or create new instances.
Multiple PSQL instances can be created, each configured to the same or different backend databases. But over time a `Notebook` can have only one PSQL interpreter instance `bound`. That means you _can not_ connect to different databases in the same `Notebook`. This is a known Zeppelin limitation.
Multiple PSQL instances can be created, each configured to the same or different backend databases. But over time a `Notebook` can have only one PSQL interpreter instance `bound`. That means you _cannot_ connect to different databases in the same `Notebook`. This is a known Zeppelin limitation.
To create new PSQL instance open the `Interprter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `psql`. Then follow the configuration instructions and `Save` the new instance.
To create new PSQL instance open the `Interpreter` section and click the `+Create` button. Pick a `Name` of your choice and from the `Interpreter` drop-down select `psql`. Then follow the configuration instructions and `Save` the new instance.
> Note: The `Name` of the instance is used only to distinct the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%psql.sql` tag.
> Note: The `Name` of the instance is used only to distinct the instances while binding them to the `Notebook`. The `Name` is irrelevant inside the `Notebook`. In the `Notebook` you must use `%psql.sql` tag.
### Bind to Notebook
In the `Notebook` click on the `settings` icon in the top right corner. The select/deselect the interpreters to be bound with the `Notebook`.
@ -51,7 +51,7 @@ In the `Notebook` click on the `settings` icon in the top right corner. The sele
### Configuration
You can modify the configuration of the PSQL from the `Interpreter` section. The PSQL interpreter expenses the following properties:
<table class="table-configuration">
<tr>
<th>Property Name</th>
@ -84,15 +84,15 @@ You can modify the configuration of the PSQL from the `Interpreter` section. Th
<td>1000</td>
</tr>
</table>
### How to use
```
Tip: Use (CTRL + .) for SQL auto-completion.
```
#### DDL and SQL commands
Start the paragraphs with the full `%psql.sql` prefix tag! The short notation: `%psql` would still be able run the queries but the syntax highlighting and the auto-completions will be disabled.
Start the paragraphs with the full `%psql.sql` prefix tag! The short notation: `%psql` would still be able run the queries but the syntax highlighting and the auto-completions will be disabled.
You can use the standard CREATE / DROP / INSERT commands to create or modify the data model:
@ -147,14 +147,14 @@ This will produce output like this:
#### Apply Zeppelin Dynamic Forms
You can leverage [Zepplein Dynamic Form](https://zeppelin.incubator.apache.org/docs/manual/dynamicform.html) inside your queries. You can use both the `text input` and `select form` parametrization features
You can leverage [Zeppelin Dynamic Form](../manual/dynamicform.html) inside your queries. You can use both the `text input` and `select form` parametrization features
```sql
%psql.sql
SELECT ${group_by}, count(*) as count
FROM retail_demo.order_lineitems_pxf
GROUP BY ${group_by=product_id,product_id|product_name|customer_id|store_id}
ORDER BY count ${order=DESC,DESC|ASC}
SELECT ${group_by}, count(*) as count
FROM retail_demo.order_lineitems_pxf
GROUP BY ${group_by=product_id,product_id|product_name|customer_id|store_id}
ORDER BY count ${order=DESC,DESC|ASC}
LIMIT ${limit=10};
```
#### Example HAWQ PXF/HDFS Tables
@ -172,9 +172,7 @@ And retrieve content
```sql
%psql.sql
seelect * from retail_demo.payment_methods_pxf
select * from retail_demo.payment_methods_pxf
```
### Auto-completion
The PSQL Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggesntions in a pop-up window. In addition to the SQL keyword the interpter provides suggestions for the Schema, Table, Column names as well.
### Auto-completion
The PSQL Interpreter provides a basic auto-completion functionality. On `(Ctrl+.)` it list the most relevant suggestions in a pop-up window. In addition to the SQL keyword the interpreter provides suggestions for the Schema, Table, Column names as well.

View file

@ -7,7 +7,7 @@ group: manual
{% include JB/setup %}
## Spark
## Spark Interpreter
[Apache Spark](http://spark.apache.org) is supported in Zeppelin with
Spark Interpreter group, which consisted of 4 interpreters.
@ -41,10 +41,54 @@ Spark Interpreter group, which consisted of 4 interpreters.
</table>
<br /><br />
### Configuration
<hr />
Without any configuration, Spark interpreter works out of box in local mode. But if you want to connect to your Spark cluster, you'll need following two simple steps.
#### 1. export SPARK_HOME
In **conf/zeppelin-env.sh**, export SPARK_HOME environment variable with your Spark installation path.
for example
```bash
export SPARK_HOME=/usr/lib/spark
```
You can optionally export HADOOP\_CONF\_DIR and SPARK\_SUBMIT\_OPTIONS
```bash
export HADOOP_CONF_DIR=/usr/lib/hadoop
export SPARK_SUBMIT_OPTIONS="--packages com.databricks:spark-csv_2.10:1.2.0"
```
<br />
#### 2. set master in Interpreter menu.
After start Zeppelin, go to **Interpreter** menu and edit **master** property in your Spark interpreter setting. The value may vary depending on your Spark cluster deployment type.
for example,
* **local[*]** in local mode
* **spark://master:7077** in standalone cluster
* **yarn-client** in Yarn client mode
* **mesos://host:5050** in Mesos cluster
<br />
That's it. Zeppelin will work with any version of Spark and any deployment type without rebuild Zeppelin in this way. (Zeppelin 0.5.5-incubating release works up to Spark 1.5.1)
Note that without exporting SPARK_HOME, it's running in local mode with included version of Spark. The included version may vary depending on the build profile.
<br /> <br />
### SparkContext, SQLContext, ZeppelinContext
<hr />
SparkContext, SQLContext, ZeppelinContext are automatically created and exposed as variable names 'sc', 'sqlContext' and 'z', respectively, both in scala and python environments.
@ -55,6 +99,7 @@ Note that scala / python environment shares the same SparkContext, SQLContext, Z
<br />
<br />
### Dependency Management
<hr />
There are two ways to load external library in spark interpreter. First is using Zeppelin's %dep interpreter and second is loading Spark properties.
#### 1. Dynamic Dependency Loading via %dep interpreter
@ -141,7 +186,6 @@ Note that adding jar to pyspark is only availabe via %dep interpreter at the mom
<br/>
Here are few examples:
##### 0.5.5 and later
* SPARK\_SUBMIT\_OPTIONS in conf/zeppelin-env.sh
export SPARK_SUBMIT_OPTIONS="--packages com.databricks:spark-csv_2.10:1.2.0 --jars /path/mylib1.jar,/path/mylib2.jar --files /path/mylib1.py,/path/mylib2.zip,/path/mylib3.egg"
@ -152,18 +196,10 @@ Here are few examples:
spark.jars.packages com.databricks:spark-csv_2.10:1.2.0
spark.files /path/mylib1.py,/path/mylib2.egg,/path/mylib3.zip
##### 0.5.0
* ZEPPELIN\_JAVA\_OPTS in conf/zeppelin-env.sh
export ZEPPELIN_JAVA_OPTS="-Dspark.jars=/path/mylib1.jar,/path/mylib2.jar -Dspark.files=/path/myfile1.dat,/path/myfile2.dat"
<br />
<a name="zeppelincontext"> </a>
<br />
<br />
### ZeppelinContext
<hr />
Zeppelin automatically injects ZeppelinContext as variable 'z' in your scala/python environment. ZeppelinContext provides some additional functions and utility.
@ -218,4 +254,4 @@ In sql environment, you can create form in simple template.
select * from ${table=defaultTableName} where text like '%${search}%'
```
To learn more about dynamic form, checkout [Dynamic Form](../dynamicform.html).
To learn more about dynamic form, checkout [Dynamic Form](../manual/dynamicform.html).

View file

@ -37,12 +37,12 @@ To create text input form, use _${formName}_ templates.
for example
<img src="../../assets/themes/zeppelin/img/screenshots/form_input.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_input.png" />
Also you can provide default value, using _${formName=defaultValue}_.
<img src="../../assets/themes/zeppelin/img/screenshots/form_input_default.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_input_default.png" />
<br />
@ -52,11 +52,11 @@ To create select form, use _${formName=defaultValue,option1|option2...}_
for example
<img src="../../assets/themes/zeppelin/img/screenshots/form_select.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_select.png" />
Also you can separate option's display name and value, using _${formName=defaultValue,option1(DisplayName)|option2(DisplayName)...}_
<img src="../../assets/themes/zeppelin/img/screenshots/form_select_displayname.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_select_displayname.png" />
<br />
### Creates Programmatically
@ -68,38 +68,43 @@ Here're some examples.
Text input form
You can do this in Scala
```scala
%spark
println("Hello "+z.input("name"))
```
Or Python
```python
%pyspark
print("Hello "+z.input("name"))
```
<img src="../../assets/themes/zeppelin/img/screenshots/form_input_prog.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_input_prog.png" />
Text input form with default value
Scala
```scala
%spark
println("Hello "+z.input("name", "sun"))
```
Python
```python
%pyspark
print("Hello "+z.input("name", "sun"))
```
<img src="../../assets/themes/zeppelin/img/screenshots/form_input_default_prog.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_input_default_prog.png" />
Select form
Scala
```scala
%spark
println("Hello "+z.select("day", Seq(("1","mon"),
@ -112,6 +117,7 @@ println("Hello "+z.select("day", Seq(("1","mon"),
```
Python
```python
%pyspark
print("Hello "+z.select("day", [("1","mon"),
@ -123,4 +129,4 @@ print("Hello "+z.select("day", [("1","mon"),
("7","sun")]))
```
<img src="../../assets/themes/zeppelin/img/screenshots/form_select_prog.png" />
<img src="/assets/themes/zeppelin/img/screenshots/form_select_prog.png" />

View file

@ -32,13 +32,13 @@ Zeppelin Interpreter is the plug-in which enable zeppelin user to use a specific
When you click on the ```+Create``` button in the interpreter page the interpreter drop-down list box will present all the available interpreters on your server.
<img src="../../assets/themes/zeppelin/img/screenshots/interpreter_create.png">
<img src="/assets/themes/zeppelin/img/screenshots/interpreter_create.png">
### What is zeppelin interpreter setting?
Zeppelin interpreter setting is the configuration of a given interpreter on zeppelin server. For example, the properties requried for hive JDBC interpreter to connect to the Hive server.
<img src="../../assets/themes/zeppelin/img/screenshots/interpreter_setting.png">
<img src="/assets/themes/zeppelin/img/screenshots/interpreter_setting.png">
### What is zeppelin interpreter group?
Every Interpreter belongs to an InterpreterGroup. InterpreterGroup is a unit of start/stop interpreter.
@ -48,7 +48,7 @@ SparkSQL and the dependency loader.
Technically, Zeppelin interpreters from the same group are running in the same JVM.
Interpreters belong to a single group a registered together and all of their properties are listed in the interpreter setting.
<img src="../../assets/themes/zeppelin/img/screenshots/interpreter_setting_spark.png">
<img src="/assets/themes/zeppelin/img/screenshots/interpreter_setting_spark.png">
### Programming langages for interpreter

View file

@ -51,7 +51,7 @@ The process for creating your homepage is very simple as shown below:
for example
<img src="../../assets/themes/zeppelin/img/screenshots/homepage_notebook_id.png" />
<img src="/assets/themes/zeppelin/img/screenshots/homepage_notebook_id.png" />
Set the notebook id to the ```ZEPPELIN_NOTEBOOK_HOMESCREEN``` environment variable
or ```zeppelin.notebook.homescreen``` property.
@ -97,7 +97,7 @@ you need to do is use our %angular support.
```
After running the notebook you will see output similar to this one:
<img src="../../assets/themes/zeppelin/img/screenshots/homepage_notebook_list.png" />
<img src="/assets/themes/zeppelin/img/screenshots/homepage_notebook_list.png" />
The main trick here relays in linking the ```<div>``` to the controller:

View file

@ -328,15 +328,6 @@
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.7</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.3.1</version>

View file

@ -284,6 +284,12 @@ public class PySparkInterpreter extends Interpreter implements ExecuteResultHand
@Override
public InterpreterResult interpret(String st, InterpreterContext context) {
SparkInterpreter sparkInterpreter = getSparkInterpreter();
if (sparkInterpreter.getSparkVersion().isUnsupportedVersion()) {
return new InterpreterResult(Code.ERROR, "Spark "
+ sparkInterpreter.getSparkVersion().toString() + " is not supported");
}
if (!pythonscriptRunning) {
return new InterpreterResult(Code.ERROR, "python process not running"
+ outputStream.toString());
@ -314,7 +320,6 @@ public class PySparkInterpreter extends Interpreter implements ExecuteResultHand
+ outputStream.toString());
}
SparkInterpreter sparkInterpreter = getSparkInterpreter();
if (!sparkInterpreter.getSparkVersion().isPysparkSupported()) {
return new InterpreterResult(Code.ERROR, "pyspark "
+ sparkInterpreter.getSparkContext().version() + " is not supported");

View file

@ -605,6 +605,11 @@ public class SparkInterpreter extends Interpreter {
*/
@Override
public InterpreterResult interpret(String line, InterpreterContext context) {
if (sparkVersion.isUnsupportedVersion()) {
return new InterpreterResult(Code.ERROR, "Spark " + sparkVersion.toString()
+ " is not supported");
}
z.setInterpreterContext(context);
if (line == null || line.trim().length() == 0) {
return new InterpreterResult(Code.SUCCESS);

View file

@ -115,9 +115,14 @@ public class SparkSqlInterpreter extends Interpreter {
@Override
public InterpreterResult interpret(String st, InterpreterContext context) {
SQLContext sqlc = null;
SparkInterpreter sparkInterpreter = getSparkInterpreter();
if (sparkInterpreter.getSparkVersion().isUnsupportedVersion()) {
return new InterpreterResult(Code.ERROR, "Spark "
+ sparkInterpreter.getSparkVersion().toString() + " is not supported");
}
sqlc = getSparkInterpreter().getSQLContext();
SparkContext sc = sqlc.sparkContext();
if (concurrentSQL()) {
sc.setLocalProperty("spark.scheduler.pool", "fair");

View file

@ -16,29 +16,47 @@
*/
package org.apache.zeppelin.spark;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Provide reading comparing capability of spark version returned from SparkContext.version()
*/
public enum SparkVersion {
SPARK_1_0_0,
SPARK_1_0_1,
SPARK_1_1_0,
SPARK_1_1_1,
SPARK_1_2_0,
SPARK_1_2_1,
SPARK_1_2_2,
SPARK_1_3_0,
SPARK_1_3_1,
SPARK_1_4_0,
SPARK_1_4_1,
SPARK_1_5_0,
SPARK_1_5_1,
SPARK_1_5_2;
public class SparkVersion {
Logger logger = LoggerFactory.getLogger(SparkVersion.class);
public static final SparkVersion SPARK_1_0_0 = SparkVersion.fromVersionString("1.0.0");
public static final SparkVersion SPARK_1_1_0 = SparkVersion.fromVersionString("1.1.0");
public static final SparkVersion SPARK_1_2_0 = SparkVersion.fromVersionString("1.2.0");
public static final SparkVersion SPARK_1_3_0 = SparkVersion.fromVersionString("1.3.0");
public static final SparkVersion SPARK_1_4_0 = SparkVersion.fromVersionString("1.4.0");
public static final SparkVersion SPARK_1_5_0 = SparkVersion.fromVersionString("1.5.0");
public static final SparkVersion SPARK_1_6_0 = SparkVersion.fromVersionString("1.6.0");
public static final SparkVersion MIN_SUPPORTED_VERSION = SPARK_1_0_0;
public static final SparkVersion UNSUPPORTED_FUTURE_VERSION = SPARK_1_6_0;
private int version;
private String versionString;
SparkVersion() {
version = Integer.parseInt(name().substring("SPARK_".length()).replaceAll("_", ""));
SparkVersion(String versionString) {
this.versionString = versionString;
try {
int pos = versionString.indexOf('-');
String numberPart = versionString;
if (pos > 0) {
numberPart = versionString.substring(0, pos);
}
version = Integer.parseInt(numberPart.replaceAll("\\.", ""));
} catch (Exception e) {
logger.error("Can not recognize Spark version " + versionString +
". Assume it's a future release", e);
// assume it is future release
version = 999;
}
}
public int toNumber() {
@ -46,17 +64,16 @@ public enum SparkVersion {
}
public String toString() {
return name().substring("SPARK_".length()).replaceAll("_", ".");
return versionString;
}
public boolean isUnsupportedVersion() {
return olderThan(MIN_SUPPORTED_VERSION) || newerThanEquals(UNSUPPORTED_FUTURE_VERSION);
}
public static SparkVersion fromVersionString(String versionString) {
for (SparkVersion v : values()) {
// Check for the beginning of the version string to allow for "1.5.0-SNAPSHOT"
if (versionString.startsWith(v.toString())) {
return v;
}
}
throw new IllegalArgumentException();
return new SparkVersion(versionString);
}
public boolean isPysparkSupported() {
@ -79,6 +96,10 @@ public enum SparkVersion {
return this.olderThan(SPARK_1_3_0);
}
public boolean equals(Object versionToCompare) {
return version == ((SparkVersion) versionToCompare).version;
}
public boolean newerThan(SparkVersion versionToCompare) {
return version > versionToCompare.version;
}

View file

@ -22,11 +22,24 @@ import org.junit.Test;
public class SparkVersionTest {
@Test
public void testUnknownSparkVersion() {
assertEquals(999, SparkVersion.fromVersionString("DEV-10.10").toNumber());
}
@Test
public void testUnsupportedVersion() {
assertTrue(SparkVersion.fromVersionString("9.9.9").isUnsupportedVersion());
assertFalse(SparkVersion.fromVersionString("1.5.9").isUnsupportedVersion());
assertTrue(SparkVersion.fromVersionString("0.9.0").isUnsupportedVersion());
assertTrue(SparkVersion.UNSUPPORTED_FUTURE_VERSION.isUnsupportedVersion());
}
@Test
public void testSparkVersion() {
// test equals
assertTrue(SparkVersion.SPARK_1_2_0 == SparkVersion.fromVersionString("1.2.0"));
assertTrue(SparkVersion.SPARK_1_5_0 == SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
assertEquals(SparkVersion.SPARK_1_2_0, SparkVersion.fromVersionString("1.2.0"));
assertEquals(SparkVersion.SPARK_1_5_0, SparkVersion.fromVersionString("1.5.0-SNAPSHOT"));
// test newer than
assertFalse(SparkVersion.SPARK_1_2_0.newerThan(SparkVersion.SPARK_1_2_0));

View file

@ -121,7 +121,10 @@ public abstract class Interpreter {
* Called when interpreter is no longer used.
*/
public void destroy() {
getScheduler().stop();
Scheduler scheduler = getScheduler();
if (scheduler != null) {
scheduler.stop();
}
}

View file

@ -23,29 +23,21 @@ import java.util.*;
/**
* Interpreter result template.
*
* @author Leemoonsoo
*
*/
public class InterpreterResult implements Serializable {
/**
* Type of result after code execution.
*
* @author Leemoonsoo
*
*/
public static enum Code {
SUCCESS,
INCOMPLETE,
ERROR
ERROR,
KEEP_PREVIOUS_RESULT
}
/**
* Type of Data.
*
* @author Leemoonsoo
*
*/
public static enum Type {
TEXT,
@ -99,7 +91,7 @@ public class InterpreterResult implements Serializable {
int magicLength = lastType.getValue().name().length() + 1;
// 1 for the last \n or space after magic
int subStringPos = magicLength + lastType.getKey() + 1;
return msg.substring(subStringPos);
return msg.substring(subStringPos);
}
}
@ -116,7 +108,7 @@ public class InterpreterResult implements Serializable {
return lastType.getValue();
}
}
private int getIndexOfType(String msg, Type t) {
if (msg == null) {
return 0;
@ -124,7 +116,7 @@ public class InterpreterResult implements Serializable {
String typeString = "%" + t.name().toLowerCase();
return StringUtils.indexOf(msg, typeString );
}
private TreeMap<Integer, Type> buildIndexMap(String msg) {
int lastIndexOftypes = 0;
TreeMap<Integer, Type> typesLastIndexInMsg = new TreeMap<Integer, Type>();

View file

@ -329,9 +329,13 @@ public class RemoteInterpreter extends Interpreter {
public Scheduler getScheduler() {
int maxConcurrency = 10;
RemoteInterpreterProcess interpreterProcess = getInterpreterProcess();
return SchedulerFactory.singleton().createOrGetRemoteScheduler(
"remoteinterpreter_" + interpreterProcess.hashCode(), getInterpreterProcess(),
maxConcurrency);
if (interpreterProcess == null) {
return null;
} else {
return SchedulerFactory.singleton().createOrGetRemoteScheduler(
"remoteinterpreter_" + interpreterProcess.hashCode(), getInterpreterProcess(),
maxConcurrency);
}
}

View file

@ -37,7 +37,6 @@ import org.apache.zeppelin.display.AngularObjectRegistryListener;
import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.interpreter.ClassloaderInterpreter;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.Interpreter.FormType;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterContextRunner;
import org.apache.zeppelin.interpreter.InterpreterException;
@ -62,7 +61,8 @@ import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
*
* Entry point for Interpreter process.
* Accepting thrift connections from ZeppelinServer.
*/
public class RemoteInterpreterServer
extends Thread
@ -233,6 +233,11 @@ public class RemoteInterpreterServer
result = new InterpreterResult(Code.ERROR, Job.getStack(job.getException()));
} else {
result = (InterpreterResult) job.getReturn();
// in case of job abort in PENDING status, result can be null
if (result == null) {
result = new InterpreterResult(Code.KEEP_PREVIOUS_RESULT);
}
}
return convert(result,
context.getConfig(),
@ -303,8 +308,16 @@ public class RemoteInterpreterServer
@Override
public void cancel(String className, RemoteInterpreterContext interpreterContext)
throws TException {
logger.info("cancel {} {}", className, interpreterContext.getParagraphId());
Interpreter intp = getInterpreter(className);
intp.cancel(convert(interpreterContext));
String jobId = interpreterContext.getParagraphId();
Job job = intp.getScheduler().removeFromWaitingQueue(jobId);
if (job != null) {
job.setStatus(Status.ABORT);
} else {
intp.cancel(convert(interpreterContext));
}
}
@Override

View file

@ -18,6 +18,7 @@
package org.apache.zeppelin.scheduler;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
@ -25,10 +26,7 @@ import java.util.concurrent.ExecutorService;
import org.apache.zeppelin.scheduler.Job.Status;
/**
* TODO(moon) : add description.
*
* @author Leemoonsoo
*
* FIFOScheduler runs submitted job sequentially
*/
public class FIFOScheduler implements Scheduler {
List<Job> queue = new LinkedList<Job>();
@ -83,20 +81,38 @@ public class FIFOScheduler implements Scheduler {
}
}
@Override
public Job removeFromWaitingQueue(String jobId) {
synchronized (queue) {
Iterator<Job> it = queue.iterator();
while (it.hasNext()) {
Job job = it.next();
if (job.getId().equals(jobId)) {
it.remove();
return job;
}
}
}
return null;
}
@Override
public void run() {
synchronized (queue) {
while (terminate == false) {
if (runningJob != null || queue.isEmpty() == true) {
try {
queue.wait(500);
} catch (InterruptedException e) {
synchronized (queue) {
if (runningJob != null || queue.isEmpty() == true) {
try {
queue.wait(500);
} catch (InterruptedException e) {
}
continue;
}
continue;
}
runningJob = queue.remove(0);
runningJob = queue.remove(0);
}
final Scheduler scheduler = this;
this.executor.execute(new Runnable() {

View file

@ -18,6 +18,7 @@
package org.apache.zeppelin.scheduler;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
@ -25,10 +26,7 @@ import java.util.concurrent.ExecutorService;
import org.apache.zeppelin.scheduler.Job.Status;
/**
* TODO(moon) : add description.
*
* @author Leemoonsoo
*
* Parallel scheduler runs submitted job concurrently.
*/
public class ParallelScheduler implements Scheduler {
List<Job> queue = new LinkedList<Job>();
@ -63,6 +61,21 @@ public class ParallelScheduler implements Scheduler {
return ret;
}
@Override
public Job removeFromWaitingQueue(String jobId) {
synchronized (queue) {
Iterator<Job> it = queue.iterator();
while (it.hasNext()) {
Job job = it.next();
if (job.getId().equals(jobId)) {
it.remove();
return job;
}
}
}
return null;
}
@Override
public Collection<Job> getJobsRunning() {
List<Job> ret = new LinkedList<Job>();
@ -87,9 +100,9 @@ public class ParallelScheduler implements Scheduler {
@Override
public void run() {
synchronized (queue) {
while (terminate == false) {
while (terminate == false) {
Job job = null;
synchronized (queue) {
if (running.size() >= maxConcurrency || queue.isEmpty() == true) {
try {
queue.wait(500);
@ -98,14 +111,12 @@ public class ParallelScheduler implements Scheduler {
continue;
}
Job job = queue.remove(0);
job = queue.remove(0);
running.add(job);
Scheduler scheduler = this;
executor.execute(new JobRunner(scheduler, job));
}
Scheduler scheduler = this;
executor.execute(new JobRunner(scheduler, job));
}
}

View file

@ -18,6 +18,7 @@
package org.apache.zeppelin.scheduler;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
@ -32,7 +33,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* RemoteScheduler runs in ZeppelinServer and proxies Scheduler running on RemoteInterpreter
*/
public class RemoteScheduler implements Scheduler {
Logger logger = LoggerFactory.getLogger(RemoteScheduler.class);
@ -107,6 +108,21 @@ public class RemoteScheduler implements Scheduler {
return ret;
}
@Override
public Job removeFromWaitingQueue(String jobId) {
synchronized (queue) {
Iterator<Job> it = queue.iterator();
while (it.hasNext()) {
Job job = it.next();
if (job.getId().equals(jobId)) {
it.remove();
return job;
}
}
}
return null;
}
@Override
public Collection<Job> getJobsRunning() {
List<Job> ret = new LinkedList<Job>();

View file

@ -20,10 +20,7 @@ package org.apache.zeppelin.scheduler;
import java.util.Collection;
/**
* TODO(moon) : add description.
*
* @author Leemoonsoo
*
* Interface for scheduler
*/
public interface Scheduler extends Runnable {
public String getName();
@ -34,5 +31,7 @@ public interface Scheduler extends Runnable {
public void submit(Job job);
public Job removeFromWaitingQueue(String jobId);
public void stop();
}

View file

@ -88,7 +88,30 @@ public class FIFOSchedulerTest extends TestCase {
assertTrue((500 > (Long)job1.getReturn()));
assertEquals(null, job2.getReturn());
}
public void testRemoveFromWaitingQueue() throws InterruptedException{
Scheduler s = schedulerSvc.createOrGetFIFOScheduler("test");
assertEquals(0, s.getJobsRunning().size());
assertEquals(0, s.getJobsWaiting().size());
Job job1 = new SleepingJob("job1", null, 500);
Job job2 = new SleepingJob("job2", null, 500);
s.submit(job1);
s.submit(job2);
Thread.sleep(200);
job1.abort();
job2.abort();
Thread.sleep(200);
assertEquals(Status.ABORT, job1.getStatus());
assertEquals(Status.ABORT, job2.getStatus());
assertTrue((500 > (Long)job1.getReturn()));
assertEquals(null, job2.getReturn());
}
}

View file

@ -18,6 +18,8 @@
package org.apache.zeppelin.scheduler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
@ -33,6 +35,7 @@ import org.apache.zeppelin.interpreter.InterpreterContextRunner;
import org.apache.zeppelin.interpreter.InterpreterGroup;
import org.apache.zeppelin.interpreter.remote.RemoteInterpreter;
import org.apache.zeppelin.interpreter.remote.mock.MockInterpreterA;
import org.apache.zeppelin.scheduler.Job.Status;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@ -127,7 +130,7 @@ public class RemoteSchedulerTest {
Thread.sleep(TICK_WAIT);
cycles++;
}
assertTrue(job.isTerminated());
assertEquals(0, scheduler.getJobsWaiting().size());
assertEquals(0, scheduler.getJobsRunning().size());
@ -136,4 +139,133 @@ public class RemoteSchedulerTest {
schedulerSvc.removeScheduler("test");
}
@Test
public void testAbortOnPending() throws Exception {
Properties p = new Properties();
final InterpreterGroup intpGroup = new InterpreterGroup();
Map<String, String> env = new HashMap<String, String>();
env.put("ZEPPELIN_CLASSPATH", new File("./target/test-classes").getAbsolutePath());
final RemoteInterpreter intpA = new RemoteInterpreter(
p,
MockInterpreterA.class.getName(),
new File("../bin/interpreter.sh").getAbsolutePath(),
"fake",
env,
10 * 1000
);
intpGroup.add(intpA);
intpA.setInterpreterGroup(intpGroup);
intpA.open();
Scheduler scheduler = schedulerSvc.createOrGetRemoteScheduler("test",
intpA.getInterpreterProcess(),
10);
Job job1 = new Job("jobId1", "jobName1", null, 200) {
InterpreterContext context = new InterpreterContext(
"note",
"jobId1",
"title",
"text",
new HashMap<String, Object>(),
new GUI(),
new AngularObjectRegistry(intpGroup.getId(), null),
new LinkedList<InterpreterContextRunner>());
@Override
public int progress() {
return 0;
}
@Override
public Map<String, Object> info() {
return null;
}
@Override
protected Object jobRun() throws Throwable {
intpA.interpret("1000", context);
return "1000";
}
@Override
protected boolean jobAbort() {
if (isRunning()) {
intpA.cancel(context);
}
return true;
}
};
Job job2 = new Job("jobId2", "jobName2", null, 200) {
InterpreterContext context = new InterpreterContext(
"note",
"jobId2",
"title",
"text",
new HashMap<String, Object>(),
new GUI(),
new AngularObjectRegistry(intpGroup.getId(), null),
new LinkedList<InterpreterContextRunner>());
@Override
public int progress() {
return 0;
}
@Override
public Map<String, Object> info() {
return null;
}
@Override
protected Object jobRun() throws Throwable {
intpA.interpret("1000", context);
return "1000";
}
@Override
protected boolean jobAbort() {
if (isRunning()) {
intpA.cancel(context);
}
return true;
}
};
job2.setResult("result2");
scheduler.submit(job1);
scheduler.submit(job2);
int cycles = 0;
while (!job1.isRunning() && cycles < MAX_WAIT_CYCLES) {
Thread.sleep(TICK_WAIT);
cycles++;
}
assertTrue(job1.isRunning());
assertTrue(job2.getStatus() == Status.PENDING);
job2.abort();
cycles = 0;
while (!job1.isTerminated() && cycles < MAX_WAIT_CYCLES) {
Thread.sleep(TICK_WAIT);
cycles++;
}
assertNotNull(job1.getDateFinished());
assertTrue(job1.isTerminated());
assertNull(job2.getDateFinished());
assertTrue(job2.isTerminated());
assertEquals("result2", job2.getReturn());
intpA.close();
schedulerSvc.removeScheduler("test");
}
}

View file

@ -85,7 +85,7 @@ public class ZeppelinServer extends Application {
jettyServer = setupJettyServer(conf);
// REST api
final ServletContextHandler restApi = setupRestApiContextHandler();
final ServletContextHandler restApi = setupRestApiContextHandler(conf);
// Notebook server
final ServletContextHandler notebook = setupNotebookServer(conf);
@ -170,7 +170,7 @@ public class ZeppelinServer extends Application {
ServletContextHandler.SESSIONS);
cxfContext.setSessionHandler(new SessionHandler());
cxfContext.setContextPath("/");
cxfContext.setContextPath(conf.getServerContextPath());
cxfContext.addServlet(servletHolder, "/ws/*");
cxfContext.addFilter(new FilterHolder(CorsFilter.class), "/*",
EnumSet.allOf(DispatcherType.class));
@ -210,7 +210,7 @@ public class ZeppelinServer extends Application {
return scf.getSslContext();
}
private static ServletContextHandler setupRestApiContextHandler() {
private static ServletContextHandler setupRestApiContextHandler(ZeppelinConfiguration conf) {
final ServletHolder cxfServletHolder = new ServletHolder(new CXFNonSpringJaxrsServlet());
cxfServletHolder.setInitParameter("javax.ws.rs.Application", ZeppelinServer.class.getName());
cxfServletHolder.setName("rest");
@ -218,8 +218,8 @@ public class ZeppelinServer extends Application {
final ServletContextHandler cxfContext = new ServletContextHandler();
cxfContext.setSessionHandler(new SessionHandler());
cxfContext.setContextPath("/api");
cxfContext.addServlet(cxfServletHolder, "/*");
cxfContext.setContextPath(conf.getServerContextPath());
cxfContext.addServlet(cxfServletHolder, "/api/*");
cxfContext.addFilter(new FilterHolder(CorsFilter.class), "/*",
EnumSet.allOf(DispatcherType.class));
@ -230,12 +230,12 @@ public class ZeppelinServer extends Application {
ZeppelinConfiguration conf) {
WebAppContext webApp = new WebAppContext();
webApp.setContextPath(conf.getServerContextPath());
File warPath = new File(conf.getString(ConfVars.ZEPPELIN_WAR));
if (warPath.isDirectory()) {
// Development mode, read from FS
// webApp.setDescriptor(warPath+"/WEB-INF/web.xml");
webApp.setResourceBase(warPath.getPath());
webApp.setContextPath("/");
webApp.setParentLoaderPriority(true);
} else {
// use packaged WAR

View file

@ -55,6 +55,8 @@ public class Message {
CLONE_NOTE, // [c-s] clone new notebook
// @param id id of note to clone
// @param name name fpor the cloned note
IMPORT_NOTE, // [c-s] import notebook
// @param object notebook
NOTE_UPDATE,
RUN_PARAGRAPH, // [c-s] run paragraph

View file

@ -16,20 +16,17 @@
*/
package org.apache.zeppelin.socket;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import javax.servlet.http.HttpServletRequest;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
import org.apache.zeppelin.display.AngularObject;
import org.apache.zeppelin.display.AngularObjectRegistry;
import org.apache.zeppelin.display.AngularObjectRegistryListener;
import org.apache.zeppelin.display.Input;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.InterpreterSetting;
import org.apache.zeppelin.notebook.JobListenerFactory;
@ -119,6 +116,9 @@ public class NotebookServer extends WebSocketServlet implements
case CLONE_NOTE:
cloneNote(conn, notebook, messagereceived);
break;
case IMPORT_NOTE:
importNote(conn, notebook, messagereceived);
break;
case COMMIT_PARAGRAPH:
updateParagraph(conn, notebook, messagereceived);
break;
@ -171,7 +171,7 @@ public class NotebookServer extends WebSocketServlet implements
}
}
private Message deserializeMessage(String msg) {
protected Message deserializeMessage(String msg) {
return gson.fromJson(msg, Message.class);
}
@ -467,6 +467,61 @@ public class NotebookServer extends WebSocketServlet implements
broadcastNoteList();
}
protected Note importNote(NotebookSocket conn, Notebook notebook, Message fromMessage)
throws IOException {
Note note = notebook.createNote();
if (fromMessage != null) {
String noteName = (String) ((Map) fromMessage.get("notebook")).get("name");
if (noteName == null || noteName.isEmpty()) {
noteName = "Note " + note.getId();
}
note.setName(noteName);
ArrayList<Map> paragraphs = ((Map<String, ArrayList>) fromMessage.get("notebook"))
.get("paragraphs");
if (paragraphs.size() > 0) {
for (Map paragraph : paragraphs) {
try {
Paragraph p = note.addParagraph();
String text = (String) paragraph.get("text");
p.setText(text);
p.setTitle((String) paragraph.get("title"));
Map<String, Object> params = (Map<String, Object>) ((Map) paragraph
.get("settings")).get("params");
Map<String, Input> forms = (Map<String, Input>) ((Map) paragraph
.get("settings")).get("forms");
if (params != null) {
p.settings.setParams(params);
}
if (forms != null) {
p.settings.setForms(forms);
}
Map<String, Object> result = (Map) paragraph.get("result");
if (result != null) {
InterpreterResult.Code code = InterpreterResult.Code
.valueOf((String) result.get("code"));
InterpreterResult.Type type = InterpreterResult.Type
.valueOf((String) result.get("type"));
String msg = (String) result.get("msg");
p.setReturn(new InterpreterResult(code, type, msg), null);
}
Map<String, Object> config = (Map<String, Object>) paragraph
.get("config");
p.setConfig(config);
} catch (Exception e) {
LOG.error("Exception while setting parameter in paragraph", e);
}
}
}
}
note.persist();
broadcastNote(note);
broadcastNoteList();
return note;
}
private void removeParagraph(NotebookSocket conn, Notebook notebook,
Message fromMessage) throws IOException {
final String paragraphId = (String) fromMessage.get("id");

View file

@ -299,7 +299,7 @@ public class ZeppelinIT {
notebookTitles.add(el.getText());
}
WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a"));
WebElement createNoteLink = driver.findElement(By.xpath("//div[contains(@class, \"col-md-4\")]/div/h5/a[contains(.,'Create new note')]"));
createNoteLink.click();
WebDriverWait block = new WebDriverWait(driver, 10);

View file

@ -18,6 +18,7 @@
package org.apache.zeppelin.rest;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -155,8 +156,11 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
Note note = ZeppelinServer.notebook.createNote();
note.addParagraph();
Paragraph p = note.getLastParagraph();
Map config = p.getConfig();
config.put("enabled", true);
// run markdown paragraph
p.setConfig(config);
p.setText("%md markdown");
note.run(p.getId());
while (p.getStatus() != Status.FINISHED) {
@ -175,6 +179,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
// run markdown paragraph, again
p = note.addParagraph();
p.setConfig(config);
p.setText("%md markdown restarted");
note.run(p.getId());
while (p.getStatus() != Status.FINISHED) {
@ -262,6 +267,9 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi {
assertNotNull("can't create new note", note);
note.setName("source note for clone");
Paragraph paragraph = note.addParagraph();
Map config = paragraph.getConfig();
config.put("enabled", true);
paragraph.setConfig(config);
paragraph.setText("%md This is my new paragraph in my new note");
note.persist();
String sourceNoteID = note.getId();

View file

@ -20,7 +20,9 @@ import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.zeppelin.interpreter.InterpreterSetting;
@ -52,7 +54,9 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
}
private void waitForFinish(Paragraph p) {
while (p.getStatus() != Status.FINISHED) {
while (p.getStatus() != Status.FINISHED
&& p.getStatus() != Status.ERROR
&& p.getStatus() != Status.ABORT) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
@ -68,9 +72,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
// run markdown paragraph, again
Paragraph p = note.addParagraph();
Map config = p.getConfig();
config.put("enabled", true);
p.setConfig(config);
p.setText("%spark print(sc.parallelize(1 to 10).reduce(_ + _))");
note.run(p.getId());
waitForFinish(p);
assertEquals(Status.FINISHED, p.getStatus());
assertEquals("55", p.getResult().message());
ZeppelinServer.notebook.removeNote(note.id());
}
@ -84,9 +92,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
if (isPyspark() && sparkVersion >= 12) { // pyspark supported from 1.2.1
// run markdown paragraph, again
Paragraph p = note.addParagraph();
Map config = p.getConfig();
config.put("enabled", true);
p.setConfig(config);
p.setText("%pyspark print(sc.parallelize(range(1, 11)).reduce(lambda a, b: a + b))");
note.run(p.getId());
waitForFinish(p);
assertEquals(Status.FINISHED, p.getStatus());
assertEquals("55\n", p.getResult().message());
}
ZeppelinServer.notebook.removeNote(note.id());
@ -102,10 +114,14 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
if (isPyspark() && sparkVersion >= 14) { // auto_convert enabled from spark 1.4
// run markdown paragraph, again
Paragraph p = note.addParagraph();
Map config = p.getConfig();
config.put("enabled", true);
p.setConfig(config);
p.setText("%pyspark\nfrom pyspark.sql.functions import *\n"
+ "print(sqlContext.range(0, 10).withColumn('uniform', rand(seed=10) * 3.14).count())");
note.run(p.getId());
waitForFinish(p);
assertEquals(Status.FINISHED, p.getStatus());
assertEquals("10\n", p.getResult().message());
}
ZeppelinServer.notebook.removeNote(note.id());
@ -116,17 +132,28 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
// create new note
Note note = ZeppelinServer.notebook.createNote();
Paragraph p0 = note.addParagraph();
Map config0 = p0.getConfig();
config0.put("enabled", true);
p0.setConfig(config0);
p0.setText("%spark z.run(1)");
Paragraph p1 = note.addParagraph();
Map config1 = p1.getConfig();
config1.put("enabled", true);
p1.setConfig(config1);
p1.setText("%spark val a=10");
Paragraph p2 = note.addParagraph();
Map config2 = p2.getConfig();
config2.put("enabled", true);
p2.setConfig(config2);
p2.setText("%spark print(a)");
note.run(p0.getId());
waitForFinish(p0);
assertEquals(Status.FINISHED, p0.getStatus());
note.run(p2.getId());
waitForFinish(p2);
assertEquals(Status.FINISHED, p2.getStatus());
assertEquals("10", p2.getResult().message());
ZeppelinServer.notebook.removeNote(note.id());
@ -151,9 +178,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
// load dep
Paragraph p0 = note.addParagraph();
Map config = p0.getConfig();
config.put("enabled", true);
p0.setConfig(config);
p0.setText("%dep z.load(\"com.databricks:spark-csv_2.11:1.2.0\")");
note.run(p0.getId());
waitForFinish(p0);
assertEquals(Status.FINISHED, p0.getStatus());
// write test csv file
File tmpFile = File.createTempFile("test", "csv");
@ -161,6 +192,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
// load data using libraries from dep loader
Paragraph p1 = note.addParagraph();
p1.setConfig(config);
p1.setText("%pyspark\n" +
"from pyspark.sql import SQLContext\n" +
"print(sqlContext.read.format('com.databricks.spark.csv')" +
@ -168,6 +200,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
note.run(p1.getId());
waitForFinish(p1);
assertEquals(Status.FINISHED, p1.getStatus());
assertEquals("2\n", p1.getResult().message());
}
}
@ -178,9 +211,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi {
*/
private int getSparkVersionNumber(Note note) {
Paragraph p = note.addParagraph();
Map config = p.getConfig();
config.put("enabled", true);
p.setConfig(config);
p.setText("%spark print(sc.version)");
note.run(p.getId());
waitForFinish(p);
assertEquals(Status.FINISHED, p.getStatus());
String sparkVersion = p.getResult().message();
System.out.println("Spark version detected " + sparkVersion);
String[] split = sparkVersion.split("\\.");

View file

@ -136,6 +136,27 @@ public class NotebookServerTest extends AbstractTestRestApi {
notebook.removeNote(note1.getId());
}
@Test
public void testImportNotebook() throws IOException {
String msg = "{\"op\":\"IMPORT_NOTE\",\"data\":" +
"{\"notebook\":{\"paragraphs\": [{\"text\": \"Test " +
"paragraphs import\",\"config\":{},\"settings\":{}}]," +
"\"name\": \"Test Zeppelin notebook import\",\"config\": " +
"{}}}}";
Message messageReceived = notebookServer.deserializeMessage(msg);
Note note = null;
try {
note = notebookServer.importNote(null, notebook, messageReceived);
} catch (NullPointerException e) {
//broadcastNoteList(); failed nothing to worry.
}
assertNotEquals(null, notebook.getNote(note.getId()));
assertEquals("Test Zeppelin notebook import", notebook.getNote(note.getId()).getName());
assertEquals("Test paragraphs import", notebook.getNote(note.getId()).getParagraphs().get(0).getText());
notebook.removeNote(note.getId());
}
private NotebookSocket createWebSocket() {
NotebookSocket sock = mock(NotebookSocket.class);
when(sock.getRequest()).thenReturn(createHttpServletRequest());

View file

@ -29,7 +29,6 @@
"confirm": false,
"alert": false,
"nv": false,
"$": false,
"ace": false,
"d3": false
}

View file

@ -130,30 +130,37 @@ a.navbar-brand:hover {
.navbar-inverse .navbar-nav .open .dropdown-menu > li > a {
color: #D3D3D3;
}
.navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
padding: 5px 15px 5px 25px;
line-height: 20px;
}
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a {
color: #D3D3D3;
}
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a:hover,
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > li > a:focus {
color: #fff;
background-color: transparent;
}
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a,
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a:hover,
.navbar-inverse .navbar-nav .open .dropdown-menu > .scrollbar-container > .active > a:focus {
color: #fff;
background-color: #080808;
}
.server-status{
.server-status {
float: right;
}
.navbar-inverse .navbar-nav .open .dropdown-menu .divider {
background-color: #3071A9;
}
.navbar-inverse .navbar-collapse, .navbar-inverse .navbar-form {
border-color: #3071A9;
}
@ -210,7 +217,7 @@ a.navbar-brand:hover {
.box-heading {
position: relative;
max-width: 100%;
font-weight:300;
font-weight: 300;
white-space: nowrap;
text-overflow: ellipsis;
vertical-align: middle;
@ -310,3 +317,374 @@ This part should be removed when new version of bootstrap handles this issue.
.btn-group > .popover + .btn {
margin-left: -1px;
}
.display-inline {
display: inline;
float: left;
}
#noteImportModal .modal-body {
min-height: 420px;
overflow: hidden;
}
#noteImportModal .modal-footer {
min-height: 65px;
}
#noteImportModal .display-inline a {
background-color: #fff;
border: 1px solid #ddd;
border-radius: 5px;
color: #999;
cursor: pointer;
display: block;
float: left;
font-size: 98px;
height: 240px;
margin: 0 10px 16px;
padding-top: 60px;
text-align: center;
text-decoration: none;
width: 264px;
}
#noteImportModal .display-inline a:hover {
background-color: #eee;
}
#noteImportModal .display-inline a p {
font-size: 14px;
}
/* ------------------------------------------- */
/* Slide Top
/* ------------------------------------------- */
.slide-top {
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
}
.slide-top.ng-enter {
transform: translateY(60px);
-ms-transform: translateY(60px);
-webkit-transform: translateY(60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 0;
}
.slide-top.ng-enter-active {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
opacity: 1;
}
.slide-top.ng-leave {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-top.ng-leave-active {
transform: translateY(60px);
-ms-transform: translateY(60px);
-webkit-transform: translateY(60px);
opacity: 0;
}
.slide-top.ng-hide-add {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-top.ng-hide-add.ng-hide-add-active {
transform: translateY(60px);
-ms-transform: translateY(60px);
-webkit-transform: translateY(60px);
opacity: 0;
}
.slide-top.ng-hide-remove {
transform: translateY(60px);
-ms-transform: translateY(60px);
-webkit-transform: translateY(60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
display: block !important;
opacity: 0;
}
.slide-top.ng-hide-remove.ng-hide-remove-active {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
opacity: 1;
}
/* ------------------------------------------- */
/* Slide Right
/* ------------------------------------------- */
.slide-right {
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
}
.slide-right.ng-enter {
transform: translateX(60px);
-ms-transform: translateX(60px);
-webkit-transform: translateX(60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 0;
}
.slide-right.ng-enter-active {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
opacity: 1;
}
.slide-right.ng-leave {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-right.ng-leave-active {
transform: translateX(60px);
-ms-transform: translateX(60px);
-webkit-transform: translateX(60px);
opacity: 0;
}
.slide-right.ng-hide-add {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-right.ng-hide-add.ng-hide-add-active {
transform: translateX(60px);
-ms-transform: translateX(60px);
-webkit-transform: translateX(60px);
opacity: 0;
}
.slide-right.ng-hide-remove {
transform: translateX(60px);
-ms-transform: translateX(60px);
-webkit-transform: translateX(60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
display: block !important;
opacity: 0;
}
.slide-right.ng-hide-remove.ng-hide-remove-active {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
opacity: 1;
}
/* ------------------------------------------- */
/* Slide Left
/* ------------------------------------------- */
.slide-left {
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
}
.slide-left.ng-enter {
transform: translateX(-60px);
-ms-transform: translateX(-60px);
-webkit-transform: translateX(-60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 0;
}
.slide-left.ng-enter-active {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
opacity: 1;
}
.slide-left.ng-leave {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-left.ng-leave-active {
transform: translateX(-60px);
-ms-transform: translateX(-60px);
-webkit-transform: translateX(-60px);
opacity: 0;
}
.slide-left.ng-hide-add {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-left.ng-hide-add.ng-hide-add-active {
transform: translateX(-60px);
-ms-transform: translateX(-60px);
-webkit-transform: translateX(-60px);
opacity: 0;
}
.slide-left.ng-hide-remove {
transform: translateX(-60px);
-ms-transform: translateX(-60px);
-webkit-transform: translateX(-60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
display: block !important;
opacity: 0;
}
.slide-left.ng-hide-remove.ng-hide-remove-active {
transform: translateX(0);
-ms-transform: translateX(0);
-webkit-transform: translateX(0);
opacity: 1;
}
/* ------------------------------------------- */
/* Slide Down
/* ------------------------------------------- */
.slide-down {
-webkit-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition: all 0 cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
-webkit-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-moz-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-ms-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
-o-transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
transition-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
/* easeOutQuad */
}
.slide-down.ng-enter {
transform: translateY(-60px);
-ms-transform: translateY(-60px);
-webkit-transform: translateY(-60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 0;
}
.slide-down.ng-enter-active {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
opacity: 1;
}
.slide-down.ng-leave {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-down.ng-leave-active {
transform: translateY(-60px);
-ms-transform: translateY(-60px);
-webkit-transform: translateY(-60px);
opacity: 0;
}
.slide-down.ng-hide-add {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
opacity: 1;
}
.slide-down.ng-hide-add.ng-hide-add-active {
transform: translateY(-60px);
-ms-transform: translateY(-60px);
-webkit-transform: translateY(-60px);
opacity: 0;
}
.slide-down.ng-hide-remove {
transform: translateY(-60px);
-ms-transform: translateY(-60px);
-webkit-transform: translateY(-60px);
transition-duration: 250ms;
-webkit-transition-duration: 250ms;
display: block !important;
opacity: 0;
}
.slide-down.ng-hide-remove.ng-hide-remove-active {
transform: translateY(0);
-ms-transform: translateY(0);
-webkit-transform: translateY(0);
opacity: 1;
}

View file

@ -29,6 +29,8 @@ limitations under the License.
<h4>Notebook</h4>
<div>
<h5><a href="" data-toggle="modal" data-target="#noteImportModal" style="text-decoration: none;">
<i style="font-size: 15px;" class="fa fa-upload"></i> Import note</a></h5>
<h5><a href="" data-toggle="modal" data-target="#noteNameModal" style="text-decoration: none;">
<i style="font-size: 15px;" class="icon-notebook"></i> Create new note</a></h5>
<ul style="list-style-type: none;">

View file

@ -70,10 +70,10 @@ limitations under the License.
<span class="btn btn-primary" ng-click="addNewInterpreterSetting()">
Save
</span>
<span class="btn btn-default" ng-click="showAddNewSetting=false">
<span class="btn btn-default" ng-click="cancelInterpreterSetting()">
Cancel
</span>
</div>
</div>
</div>
</div>
</div>

View file

@ -163,6 +163,10 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl', function($scope,
});
};
$scope.cancelInterpreterSetting = function() {
$scope.showAddNewSetting = false;
};
$scope.resetNewInterpreterSetting = function() {
$scope.newInterpreterSetting = {
name : undefined,

View file

@ -280,10 +280,13 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
break;
}
}
if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
return;
}
// save dirtyText of moving paragraphs.
var prevParagraphId = $scope.note.paragraphs[newIndex].id;
angular.element('#' + paragraphId + '_paragraphColumn_main').scope().saveParagraph();
angular.element('#' + prevParagraphId + '_paragraphColumn_main').scope().saveParagraph();
websocketMsgSrv.moveParagraph(paragraphId, newIndex);
});
@ -315,6 +318,10 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
if (newIndex<0 || newIndex>=$scope.note.paragraphs.length) {
return;
}
// save dirtyText of moving paragraphs.
var nextParagraphId = $scope.note.paragraphs[newIndex].id;
angular.element('#' + paragraphId + '_paragraphColumn_main').scope().saveParagraph();
angular.element('#' + nextParagraphId + '_paragraphColumn_main').scope().saveParagraph();
websocketMsgSrv.moveParagraph(paragraphId, newIndex);
});
@ -412,7 +419,7 @@ angular.module('zeppelinWebApp').controller('NotebookCtrl', function($scope, $ro
$http.get(baseUrlSrv.getRestApiBase()+ '/notebook/interpreter/bind/' +$scope.note.id).
success(function(data, status, headers, config) {
$scope.interpreterBindings = data.body;
$scope.interpreterBindingsOrig = jQuery.extend(true, [], $scope.interpreterBindings); // to check dirty
$scope.interpreterBindingsOrig = angular.copy($scope.interpreterBindings); // to check dirty
if (callback) {
callback();
}

View file

@ -54,12 +54,14 @@ angular.module('zeppelinWebApp')
$scope.renderHtml = function() {
var retryRenderer = function() {
if ($('#p'+$scope.paragraph.id+'_html').length) {
if (angular.element('#p' + $scope.paragraph.id + '_html').length) {
try {
$('#p'+$scope.paragraph.id+'_html').html($scope.paragraph.result.msg);
angular.element('#p' + $scope.paragraph.id + '_html').html($scope.paragraph.result.msg);
$('#p'+$scope.paragraph.id+'_html').find('pre code').each(function(i, e) { hljs.highlightBlock(e); });
} catch(err) {
angular.element('#p' + $scope.paragraph.id + '_html').find('pre code').each(function(i, e) {
hljs.highlightBlock(e);
});
} catch (err) {
console.log('HTML rendering error %o', err);
}
} else {
@ -126,12 +128,16 @@ angular.module('zeppelinWebApp')
if (!config.graph.scatter) {
config.graph.scatter = {};
}
if (config.enabled === undefined) {
config.enabled = true;
}
};
$scope.getIframeDimensions = function () {
if ($scope.asIframe) {
var paragraphid = '#' + $routeParams.paragraphId + '_container';
var height = $(paragraphid).height();
var height = angular.element(paragraphid).height();
return height;
}
return 0;
@ -266,6 +272,13 @@ angular.module('zeppelinWebApp')
$scope.dirtyText = undefined;
};
$scope.toggleEnableDisable = function () {
$scope.paragraph.config.enabled = $scope.paragraph.config.enabled ? false : true;
var newParams = angular.copy($scope.paragraph.settings.params);
var newConfig = angular.copy($scope.paragraph.config);
commitParagraph($scope.paragraph.title, $scope.paragraph.text, newConfig, newParams);
};
$scope.moveUp = function() {
$scope.$emit('moveParagraphUp', $scope.paragraph.id);
};
@ -471,7 +484,7 @@ angular.module('zeppelinWebApp')
$scope.editor.focus();
autoAdjustEditorHeight(_editor.container.id);
$(window).resize(function(){
angular.element(window).resize(function() {
autoAdjustEditorHeight(_editor.container.id);
});
@ -602,7 +615,11 @@ angular.module('zeppelinWebApp')
if ($scope.editor.completer && $scope.editor.completer.activated) { // if autocompleter is active
} else {
// fix ace editor focus issue in chrome (textarea element goes to top: -1000px after focused by cursor move)
angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top', 0);
if (parseInt(angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top').replace('px', '')) < 0) {
var position = $scope.editor.getCursorPosition();
var cursorPos = $scope.editor.renderer.$cursorLayer.getPixelPosition(position, true);
angular.element('#' + $scope.paragraph.id + '_editor > textarea').css('top', cursorPos.top);
}
var numRows;
var currentRow;
@ -636,7 +653,7 @@ angular.module('zeppelinWebApp')
var editor = $scope.editor;
var height = editor.getSession().getScreenLength() * editor.renderer.lineHeight + editor.renderer.scrollBar.getWidth();
$('#' + id).height(height.toString() + 'px');
angular.element('#' + id).height(height.toString() + 'px');
editor.resize();
};
@ -670,7 +687,7 @@ angular.module('zeppelinWebApp')
var position = $scope.editor.getCursorPosition();
var lastCursorPosition = $scope.editor.renderer.$cursorLayer.getPixelPosition(position, true);
var calculatedCursorPosition = editorPosition.top + lastCursorPosition.top + 16*lastCursorMove;
var calculatedCursorPosition = editorPosition.top + lastCursorPosition.top + lineHeight*lastCursorMove;
var scrollTargetPos;
if (calculatedCursorPosition < scrollPosition + headerHeight + scrollTriggerEdgeMargin) {
@ -685,7 +702,14 @@ angular.module('zeppelinWebApp')
scrollTargetPos = documentHeight;
}
}
angular.element('body').scrollTo(scrollTargetPos, {axis: 'y', interrupt: true, duration:200});
// cancel previous scroll animation
var bodyEl = angular.element('body');
bodyEl.stop();
bodyEl.finish();
// scroll to scrollTargetPos
bodyEl.scrollTo(scrollTargetPos, {axis: 'y', interrupt: true, duration:100});
};
var setEditorHeight = function(id, height) {
@ -739,11 +763,10 @@ angular.module('zeppelinWebApp')
var row;
if (cursorPos >= 0) {
row = cursorPos;
var column = 0;
$scope.editor.gotoLine(row, 0);
} else {
row = $scope.editor.session.getLength() - 1;
$scope.editor.gotoLine(row + 1, 0);
row = $scope.editor.session.getLength();
$scope.editor.gotoLine(row, 0);
}
$scope.scrollToCursor($scope.paragraph.id, 0);
}
@ -847,7 +870,7 @@ angular.module('zeppelinWebApp')
clearUnknownColsFromGraphOption();
// set graph height
var height = $scope.paragraph.config.graph.height;
$('#p'+$scope.paragraph.id+'_graph').height(height);
angular.element('#p' + $scope.paragraph.id + '_graph').height(height);
if (!type || type === 'table') {
setTable($scope.paragraph.result, refresh);
@ -933,16 +956,16 @@ angular.module('zeppelinWebApp')
html += '</table>';
$('#p' + $scope.paragraph.id + '_table').html(html);
$('#p' + $scope.paragraph.id + '_table').perfectScrollbar();
angular.element('#p' + $scope.paragraph.id + '_table').html(html);
angular.element('#p' + $scope.paragraph.id + '_table').perfectScrollbar();
// set table height
var height = $scope.paragraph.config.graph.height;
$('#p'+$scope.paragraph.id+'_table').height(height);
angular.element('#p' + $scope.paragraph.id + '_table').height(height);
};
var retryRenderer = function() {
if ($('#p'+$scope.paragraph.id+'_table').length) {
if (angular.element('#p' + $scope.paragraph.id + '_table').length) {
try {
renderTable();
} catch(err) {
@ -1076,7 +1099,7 @@ angular.module('zeppelinWebApp')
};
var retryRenderer = function() {
if ($('#p'+$scope.paragraph.id+'_'+type+' svg').length !== 0) {
if (angular.element('#p' + $scope.paragraph.id + '_' + type + ' svg').length !== 0) {
try {
renderChart();
} catch(err) {
@ -1751,7 +1774,7 @@ angular.module('zeppelinWebApp')
};
$scope.setGraphHeight = function() {
var height = $('#p'+$scope.paragraph.id+'_graph').height();
var height = angular.element('#p' + $scope.paragraph.id + '_graph').height();
var newParams = angular.copy($scope.paragraph.settings.params);
var newConfig = angular.copy($scope.paragraph.config);

View file

@ -73,7 +73,7 @@
border: 3px solid #DDDDDD;
}
.paragraph .paragraphFooter {
.paragraph .paragraphFooter {
height: 9px;
}
@ -182,6 +182,14 @@
color: #333333;
}
/*
Paragraph Menu
*/
.dropdown-menu > li > a {
cursor: pointer;
}
/*
Paragraph Title
*/

View file

@ -41,7 +41,7 @@ limitations under the License.
require : ['ace/ext/language_tools']
}"
ng-model="paragraph.text"
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING', 'paragraph-text--dirty' : dirtyText}">
ng-class="{'disable': paragraph.status == 'RUNNING' || paragraph.status == 'PENDING', 'paragraph-text--dirty' : dirtyText !== undefined}">
</div>
</div>
@ -410,7 +410,7 @@ limitations under the License.
<!-- Run / Cancel button -->
<span class="icon-control-play" style="cursor:pointer;color:#3071A9" tooltip-placement="top" tooltip="Run this paragraph (Shift+Enter)"
ng-click="runParagraph(getEditorValue())"
ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING'"></span>
ng-show="paragraph.status!='RUNNING' && paragraph.status!='PENDING' && paragraph.config.enabled"></span>
<span class="icon-control-pause" style="cursor:pointer;color:#CD5C5C" tooltip-placement="top" tooltip="Cancel"
ng-click="cancelParagraph()"
ng-show="paragraph.status=='RUNNING' || paragraph.status=='PENDING'"></span>
@ -418,9 +418,6 @@ limitations under the License.
ng-click="toggleEditor()"></span>
<span class="{{paragraph.config.tableHide ? 'icon-notebook' : 'icon-book-open'}}" style="cursor:pointer;" tooltip-placement="top" tooltip="{{(paragraph.config.tableHide ? 'Show' : 'Hide') + ' output'}}"
ng-click="toggleOutput()"></span>
<span style="cursor:pointer;"
ng-click="saveParagraph()"
ng-show="dirtyText"></span>
<span class="dropdown navbar-right">
<span class="icon-settings" style="cursor:pointer"
data-toggle="dropdown"
@ -428,56 +425,50 @@ limitations under the License.
</span>
<ul class="dropdown-menu" role="menu" style="width:200px;">
<li>
<a class="fa fa-arrows-h dropdown"> Width
<form style="display:inline; margin-left:5px;">
<select ng-model="paragraph.config.colWidth"
class="selectpicker"
ng-change="changeColWidth()"
ng-options="col for col in colWidthOption"></select>
</form>
<a class="dropdown"><span class="fa fa-arrows-h"></span> Width
<form style="display:inline; margin-left:5px;">
<select ng-model="paragraph.config.colWidth"
class="selectpicker"
ng-change="changeColWidth()"
ng-options="col for col in colWidthOption"></select>
</form>
</a>
</li>
<li>
<a class="icon-arrow-up" style="cursor:pointer"
ng-click="moveUp()"> Move Up</a>
<a ng-click="moveUp()"><span class="icon-arrow-up"></span> Move Up</a>
</li>
<li>
<a class="icon-arrow-down" style="cursor:pointer"
ng-click="moveDown()"> Move Down</a>
<a ng-click="moveDown()"><span class="icon-arrow-down"></span> Move Down</a>
</li>
<li>
<a class="icon-plus" style="cursor:pointer"
ng-click="insertNew()"> Insert New</a>
<a ng-click="insertNew()"><span class="icon-plus"></span> Insert New</a>
</li>
<li>
<!-- paragraph handler -->
<a class="fa fa-font" style="cursor:pointer"
ng-click="hideTitle()"
ng-show="paragraph.config.title"> Hide title</a>
<a class="fa fa-font" style="cursor:pointer"
ng-click="showTitle()"
ng-show="!paragraph.config.title"> Show title</a>
<a ng-click="hideTitle()"
ng-show="paragraph.config.title"><span class="fa fa-font"></span> Hide title</a>
<a ng-click="showTitle()"
ng-show="!paragraph.config.title"><span class="fa fa-font"></span> Show title</a>
</li>
<li>
<a class="fa fa-list-ol" style="cursor:pointer"
ng-click="hideLineNumbers()"
ng-show="paragraph.config.lineNumbers"> Hide line numbers</a>
<a class="fa fa-list-ol" style="cursor:pointer"
ng-click="showLineNumbers()"
ng-show="!paragraph.config.lineNumbers"> Show line numbers</a>
</li>
<li><a class="icon-share-alt" style="cursor:pointer"
ng-click="goToSingleParagraph()"> Link this paragraph</a>
<a ng-click="hideLineNumbers()"
ng-show="paragraph.config.lineNumbers"><span class="fa fa-list-ol"></span> Hide line numbers</a>
<a ng-click="showLineNumbers()"
ng-show="!paragraph.config.lineNumbers"><span class="fa fa-list-ol"></span> Show line numbers</a>
</li>
<li>
<a class="fa fa-eraser" style="cursor:pointer"
ng-click="clearParagraphOutput()"> Clear output</a>
<a ng-click="toggleEnableDisable()"><span class="icon-control-play"></span>
{{paragraph.config.enabled ? "Disable" : "Enable"}} run</a>
</li>
<li>
<a ng-click="goToSingleParagraph()"><span class="icon-share-alt"></span> Link this paragraph</a>
</li>
<li>
<a ng-click="clearParagraphOutput()"><span class="fa fa-eraser"></span> Clear output</a>
</li>
<li>
<!-- remove paragraph -->
<a class="fa fa-times" style="cursor:pointer"
ng-click="removeParagraph()"> Remove</a>
<a ng-click="removeParagraph()"><span class="fa fa-times"></span> Remove</a>
</li>
</ul>
</span>
@ -487,5 +478,5 @@ limitations under the License.
<div ng-show="!paragraph.config.tableHide && !viewOnly" id="{{paragraph.id}}_executionTime" class="executionTime" ng-bind-html="getExecutionTime()">
</div>
</div>
</div>

View file

@ -20,6 +20,7 @@ body {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
color: #2c3e50;
border-bottom: 1px solid #E5E5E5;
z-index: 300;
}
.editor,

View file

@ -69,3 +69,7 @@ body {
.lastEmptyParagraph {
display: none;
}
.noteAction button.btn {
border-radius: 4px !important;
}

View file

@ -32,7 +32,7 @@ angular.module('zeppelinWebApp').service('baseUrlSrv', function() {
this.getWebsocketUrl = function() {
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
return wsProtocol + '//' + location.hostname + ':' + this.getPort() + '/ws';
return wsProtocol + '//' + location.hostname + ':' + this.getPort() + skipTrailingSlash(location.pathname) + '/ws';
};
this.getRestApiBase = function() {

View file

@ -14,7 +14,9 @@
'use strict';
angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootScope, $routeParams, notebookListDataFactory, websocketMsgSrv, arrayOrderingSrv) {
angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootScope, $routeParams,
notebookListDataFactory, websocketMsgSrv,
arrayOrderingSrv) {
/** Current list of notes (ids) */
var vm = this;
@ -23,7 +25,7 @@ angular.module('zeppelinWebApp').controller('NavCtrl', function($scope, $rootSco
vm.websocketMsgSrv = websocketMsgSrv;
vm.arrayOrderingSrv = arrayOrderingSrv;
$('#notebook-list').perfectScrollbar({suppressScrollX: true});
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
$scope.$on('setNoteMenu', function(event, notes) {
notebookListDataFactory.setNotes(notes);

View file

@ -14,41 +14,45 @@
'use strict';
angular.module('zeppelinWebApp').controller('NotenameCtrl', function($scope, $rootScope, $routeParams, websocketMsgSrv) {
angular.module('zeppelinWebApp').controller('NotenameCtrl', function($scope, $rootScope, $routeParams, websocketMsgSrv, $location) {
var vm = this;
vm.websocketMsgSrv = websocketMsgSrv;
$scope.note = {};
vm.createNote = function(){
if(!vm.clone){
vm.websocketMsgSrv.createNotebook($scope.note.notename);
}else{
var noteId = $routeParams.noteId;
vm.websocketMsgSrv.cloneNotebook(noteId, $scope.note.notename);
}
vm.createNote = function() {
if (!vm.clone) {
vm.websocketMsgSrv.createNotebook($scope.note.notename);
} else {
var noteId = $routeParams.noteId;
vm.websocketMsgSrv.cloneNotebook(noteId, $scope.note.notename);
}
};
$scope.$on('setNoteContent', function(event, note) {
if(note !== undefined) {
window.location = '#/notebook/' + note.id;
console.log(note);
//a hack, to make it run only after notebook creation
//it should not run i.e in case of linking to the paragraph
if (note && $location.path().indexOf(note.id) < 0) {
$location.path('notebook/' + note.id);
}
});
vm.preVisible = function(clone){
var generatedName = vm.generateName();
$scope.note.notename = 'Note ' + generatedName;
vm.clone = clone;
$scope.$apply();
vm.preVisible = function(clone) {
var generatedName = vm.generateName();
$scope.note.notename = 'Note ' + generatedName;
vm.clone = clone;
$scope.$apply();
};
vm.generateName = function () {
var DICTIONARY = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];
var randIndex, name = '';
for (var i = 0; i < 9; i++) {
randIndex = Math.floor(Math.random() * 32);
name += DICTIONARY[randIndex];
}
return name;
};
var DICTIONARY = [ '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B',
'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' ];
var randIndex, name = '';
for (var i = 0; i < 9; i++) {
randIndex = Math.floor(Math.random() * 32);
name += DICTIONARY[randIndex];
}
return name;
};
});

View file

@ -0,0 +1,76 @@
<!--
Licensed 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.
-->
<div id="noteImportModal" class="modal fade" role="dialog"
tabindex='-1'>
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content" id="NoteImportCtrl" ng-init="NoteImportInit">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Import new note</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="noteImportName">Import AS</label>
<input placeholder="Note name" type="text" class="form-control" id="noteImportName"
ng-model="note.noteImportName">
</div>
<div class="form-group" ng-show="note.errorText">
<div class="alert alert-danger">{{note.errorText}}</div>
</div>
<div class="form-group slide-left" ng-show="note.step1">
<div class="display-inline">
<a class="fa fa-cloud-upload import-file-upload" ng-click="uploadFile()">
<p>Choose a JSON here</p>
</a>
</div>
<div style="display: none">
<input placeholder="Note name" type="file" class="form-control" id="noteImportFile"
ng-model="note.importFile" onchange="angular.element(this).scope().importFile(this)">
</div>
<div class="display-inline">
<a href="javascript:void(0);" ng-click="uploadURL()" class="fa fa-link">
<p>Add from URL</p>
</a>
</div>
</div>
<div class="form-group slide-right" ng-show="note.step2">
<label for="noteImportUrl">URL</label>
<input placeholder="Note name" type="text" class="form-control" id="noteImportUrl"
ng-model="note.importUrl">
</div>
</div>
<div class="modal-footer">
<div ng-show="note.step2">
<button type="button" id="importBackButton"
class="btn btn-default"
ng-click="noteimportctrl.importBack()">Back
</button>
<button type="button" id="importNoteButton"
class="btn btn-default"
ng-click="noteimportctrl.importNote()">Import Note
</button>
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,110 @@
/*
* Licensed 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.
*/
'use strict';
angular.module('zeppelinWebApp').controller('NoteImportCtrl', function($scope, $timeout, websocketMsgSrv) {
var vm = this;
$scope.note = {};
$scope.note.step1 = true;
$scope.note.step2 = false;
vm.resetFlags = function() {
$scope.note = {};
$scope.note.step1 = true;
$scope.note.step2 = false;
angular.element('#noteImportFile').val('');
};
$scope.uploadFile = function() {
angular.element('#noteImportFile').click();
};
$scope.importFile = function(element) {
$scope.note.errorText = '';
$scope.note.importFile = element.files[0];
var file = $scope.note.importFile;
var reader = new FileReader();
reader.onloadend = function() {
vm.processImportJson(reader.result);
};
if (file) {
reader.readAsText(file);
}
};
$scope.uploadURL = function() {
$scope.note.errorText = '';
$scope.note.step1 = false;
$timeout(function() {
$scope.note.step2 = true;
}, 400);
};
vm.importBack = function() {
$scope.note.errorText = '';
$timeout(function() {
$scope.note.step1 = true;
}, 400);
$scope.note.step2 = false;
};
vm.importNote = function() {
$scope.note.errorText = '';
if ($scope.note.importUrl) {
jQuery.getJSON($scope.note.importUrl, function(result) {
vm.processImportJson(result);
}).fail(function() {
$scope.note.errorText = 'Unable to Fetch URL';
$scope.$apply();
});
}
else {
$scope.note.errorText = 'Enter URL';
$scope.$apply();
}
};
vm.processImportJson = function(result) {
if (typeof result !== 'object') {
try {
result = JSON.parse(result);
} catch (e) {
$scope.note.errorText = 'JSON parse exception';
$scope.$apply();
return;
}
}
if (result.paragraphs && result.paragraphs.length > 0) {
if (!$scope.note.noteImportName) {
$scope.note.noteImportName = result.name;
} else {
result.name = $scope.note.noteImportName;
}
websocketMsgSrv.importNotebook(result);
//angular.element('#noteImportModal').modal('hide');
} else {
$scope.note.errorText = 'Invalid JSON';
}
$scope.$apply();
};
$scope.$on('setNoteMenu', function(event, notes) {
vm.resetFlags();
angular.element('#noteImportModal').modal('hide');
});
});

View file

@ -113,6 +113,15 @@ angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope,
});
},
importNotebook: function(notebook) {
websocketEvents.sendNewEvent({
op: 'IMPORT_NOTE',
data: {
notebook: notebook
}
});
},
isConnected: function(){
return websocketEvents.isConnected();
}

View file

@ -73,6 +73,9 @@ limitations under the License.
<div ng-controller="NotenameCtrl as notenamectrl">
<div id="note-modal-container" ng-include src="'components/noteName-create/note-name-dialog.html'"></div>
</div>
<div ng-controller="NoteImportCtrl as noteimportctrl">
<div id="note-import-container" ng-include src="'components/noteName-import/note-import-dialog.html'"></div>
</div>
<!-- build:js(.) scripts/oldieshim.js -->
<!--[if lt IE 9]>
<script src="bower_components/es5-shim/es5-shim.js"></script>
@ -129,6 +132,7 @@ limitations under the License.
<script src="components/navbar/navbar.controller.js"></script>
<script src="components/ngescape/ngescape.directive.js"></script>
<script src="components/noteName-create/notename.controller.js"></script>
<script src="components/noteName-import/notenameImport.controller.js"></script>
<script src="components/popover-html-unsafe/popover-html-unsafe.directive.js"></script>
<script src="components/ngenter/ngenter.directive.js"></script>
<script src="components/dropdowninput/dropdowninput.directive.js"></script>

View file

@ -268,6 +268,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
return getInt(ConfVars.ZEPPELIN_PORT);
}
public String getServerContextPath() {
return getString(ConfVars.ZEPPELIN_SERVER_CONTEXT_PATH);
}
public String getKeyStorePath() {
return getRelativeDir(
String.format("%s/%s",
@ -383,6 +387,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
ZEPPELIN_HOME("zeppelin.home", "../"),
ZEPPELIN_ADDR("zeppelin.server.addr", "0.0.0.0"),
ZEPPELIN_PORT("zeppelin.server.port", 8080),
ZEPPELIN_SERVER_CONTEXT_PATH("zeppelin.server.context.path", "/"),
ZEPPELIN_SSL("zeppelin.ssl", false),
ZEPPELIN_SSL_CLIENT_AUTH("zeppelin.ssl.client.auth", false),
ZEPPELIN_SSL_KEYSTORE_PATH("zeppelin.ssl.keystore.path", "keystore"),

View file

@ -294,21 +294,6 @@ public class Note implements Serializable, JobListener {
}
}
public List<Map<String, String>> generateParagraphsInfo (){
List<Map<String, String>> paragraphsInfo = new LinkedList<>();
synchronized (paragraphs) {
for (Paragraph p : paragraphs) {
Map<String, String> info = new HashMap<>();
info.put("id", p.getId());
info.put("status", p.getStatus().toString());
info.put("started", p.getDateStarted().toString());
info.put("finished", p.getDateFinished().toString());
paragraphsInfo.add(info);
}
}
return paragraphsInfo;
}
/**
* Run all paragraphs sequentially.
*
@ -334,14 +319,13 @@ public class Note implements Serializable, JobListener {
Paragraph p = getParagraph(paragraphId);
p.setNoteReplLoader(replLoader);
p.setListener(jobListenerFactory.getParagraphJobListener(this));
logger.info("Note Run Paragraph=" + p);
Interpreter intp = replLoader.get(p.getRequiredReplName());
logger.info("Note Run intp=" + intp);
if (intp == null) {
throw new InterpreterException("Interpreter " + p.getRequiredReplName() + " not found");
}
logger.info("Note Run intp=" + intp);
intp.getScheduler().submit(p);
if ((Boolean) p.getConfig().get("enabled")) {
intp.getScheduler().submit(p);
}
}
public List<String> completion(String paragraphId, String buffer, int cursor) {

View file

@ -22,6 +22,8 @@ import org.apache.zeppelin.display.GUI;
import org.apache.zeppelin.display.Input;
import org.apache.zeppelin.interpreter.*;
import org.apache.zeppelin.interpreter.Interpreter.FormType;
import org.apache.zeppelin.interpreter.InterpreterResult.Code;
import org.apache.zeppelin.interpreter.InterpreterResult.Type;
import org.apache.zeppelin.scheduler.Job;
import org.apache.zeppelin.scheduler.JobListener;
import org.slf4j.Logger;
@ -205,13 +207,22 @@ public class Paragraph extends Job implements Serializable, Cloneable {
}
logger().debug("RUN : " + script);
InterpreterResult ret = repl.interpret(script, getInterpreterContext());
if (Code.KEEP_PREVIOUS_RESULT == ret.code()) {
return getReturn();
}
return ret;
}
@Override
protected boolean jobAbort() {
Interpreter repl = getRepl(getRequiredReplName());
repl.cancel(getInterpreterContext());
Job job = repl.getScheduler().removeFromWaitingQueue(getId());
if (job != null) {
job.setStatus(Status.ABORT);
} else {
repl.cancel(getInterpreterContext());
}
return true;
}

View file

@ -214,11 +214,12 @@ public class VFSNotebookRepo implements NotebookRepo {
throw new IOException(noteDir.getName().toString() + " is not a directory");
}
FileObject noteJson = noteDir.resolveFile("note.json", NameScope.CHILD);
FileObject noteJson = noteDir.resolveFile(".note.json", NameScope.CHILD);
// false means not appending. creates file if not exists
OutputStream out = noteJson.getContent().getOutputStream(false);
out.write(json.getBytes(conf.getString(ConfVars.ZEPPELIN_ENCODING)));
out.close();
noteJson.moveTo(noteDir.resolveFile("note.json", NameScope.CHILD));
}
@Override

View file

@ -25,7 +25,9 @@ import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -47,8 +49,11 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.quartz.SchedulerException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class NotebookTest implements JobListenerFactory{
private static final Logger logger = LoggerFactory.getLogger(NotebookTest.class);
private File tmpDir;
private ZeppelinConfiguration conf;
@ -95,6 +100,9 @@ public class NotebookTest implements JobListenerFactory{
// run with defatul repl
Paragraph p1 = note.addParagraph();
Map config = p1.getConfig();
config.put("enabled", true);
p1.setConfig(config);
p1.setText("hello world");
note.run(p1.getId());
while(p1.isTerminated()==false || p1.getResult()==null) Thread.yield();
@ -102,6 +110,7 @@ public class NotebookTest implements JobListenerFactory{
// run with specific repl
Paragraph p2 = note.addParagraph();
p2.setConfig(config);
p2.setText("%mock2 hello world");
note.run(p2.getId());
while(p2.isTerminated()==false || p2.getResult()==null) Thread.yield();
@ -155,6 +164,9 @@ public class NotebookTest implements JobListenerFactory{
// run with default repl
Paragraph p1 = note.addParagraph();
Map config = p1.getConfig();
config.put("enabled", true);
p1.setConfig(config);
p1.setText("hello world");
note.persist();
@ -166,6 +178,9 @@ public class NotebookTest implements JobListenerFactory{
public void testClearParagraphOutput() throws IOException, SchedulerException{
Note note = notebook.createNote();
Paragraph p1 = note.addParagraph();
Map config = p1.getConfig();
config.put("enabled", true);
p1.setConfig(config);
p1.setText("hello world");
note.run(p1.getId());
@ -181,10 +196,14 @@ public class NotebookTest implements JobListenerFactory{
public void testRunAll() throws IOException {
Note note = notebook.createNote();
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
Paragraph p1 = note.addParagraph();
Map config = p1.getConfig();
config.put("enabled", true);
p1.setConfig(config);
p1.setText("p1");
Paragraph p2 = note.addParagraph();
Map config1 = p2.getConfig();
p2.setConfig(config1);
p2.setText("p2");
assertEquals(null, p2.getResult());
note.runAll();
@ -200,17 +219,20 @@ public class NotebookTest implements JobListenerFactory{
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
Paragraph p = note.addParagraph();
Map config = new HashMap<String, Object>();
p.setConfig(config);
p.setText("p1");
Date dateFinished = p.getDateFinished();
assertNull(dateFinished);
// set cron scheduler, once a second
Map<String, Object> config = note.getConfig();
config = note.getConfig();
config.put("enabled", true);
config.put("cron", "* * * * * ?");
note.setConfig(config);
notebook.refreshCron(note.id());
Thread.sleep(1*1000);
// remove cron scheduler.
config.put("cron", null);
note.setConfig(config);
@ -301,46 +323,35 @@ public class NotebookTest implements JobListenerFactory{
Note note = notebook.createNote();
note.getNoteReplLoader().setInterpreters(factory.getDefaultInterpreterSettingList());
Paragraph p1 = note.addParagraph();
p1.setText("p1");
Paragraph p2 = note.addParagraph();
p2.setText("p2");
Paragraph p3 = note.addParagraph();
p3.setText("p3");
Paragraph p4 = note.addParagraph();
p4.setText("p4");
ArrayList<Paragraph> paragraphs = new ArrayList<>();
for (int i = 0; i < 100; i++) {
Paragraph tmp = note.addParagraph();
tmp.setText("p" + tmp.getId());
paragraphs.add(tmp);
}
/* all jobs are ready to run */
assertEquals(Job.Status.READY, p1.getStatus());
assertEquals(Job.Status.READY, p2.getStatus());
assertEquals(Job.Status.READY, p3.getStatus());
assertEquals(Job.Status.READY, p4.getStatus());
for (Paragraph p : paragraphs) {
assertEquals(Job.Status.READY, p.getStatus());
}
/* run all */
note.runAll();
/* all are pending in the beginning (first one possibly started)*/
assertTrue(p1.getStatus() == Job.Status.PENDING || p1.getStatus() == Job.Status.RUNNING);
assertEquals(Job.Status.PENDING, p2.getStatus());
assertEquals(Job.Status.PENDING, p3.getStatus());
assertEquals(Job.Status.PENDING, p4.getStatus());
while (paragraphs.get(0).getStatus() != Status.FINISHED) Thread.yield();
/* wait till first job is terminated and second starts running */
while(p1.isTerminated() == false || (p2.getStatus() == Job.Status.PENDING)) Thread.yield();
assertEquals(Job.Status.FINISHED, p1.getStatus());
assertEquals(Job.Status.RUNNING, p2.getStatus());
assertEquals(Job.Status.PENDING, p3.getStatus());
assertEquals(Job.Status.PENDING, p4.getStatus());
/* restart interpreter */
factory.restart(note.getNoteReplLoader().getInterpreterSettings().get(0).id());
/* pending and running jobs have been aborted */
assertEquals(Job.Status.FINISHED, p1.getStatus());
assertEquals(Job.Status.ABORT, p2.getStatus());
assertEquals(Job.Status.ABORT, p3.getStatus());
assertEquals(Job.Status.ABORT, p4.getStatus());
boolean isAborted = false;
for (Paragraph p : paragraphs) {
logger.debug(p.getStatus().name());
if (isAborted) {
assertEquals(Job.Status.ABORT, p.getStatus());
}
if (p.getStatus() == Status.ABORT) {
isAborted = true;
}
}
assertTrue(isAborted);
}
private void delete(File file){
@ -355,7 +366,7 @@ public class NotebookTest implements JobListenerFactory{
file.delete();
}
}
@Override
public JobListener getParagraphJobListener(Note note) {
return new JobListener(){

View file

@ -19,11 +19,10 @@ package org.apache.zeppelin.notebook.repo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.io.FileUtils;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
@ -34,10 +33,8 @@ import org.apache.zeppelin.interpreter.mock.MockInterpreter1;
import org.apache.zeppelin.interpreter.mock.MockInterpreter2;
import org.apache.zeppelin.notebook.JobListenerFactory;
import org.apache.zeppelin.notebook.Note;
import org.apache.zeppelin.notebook.NoteInfo;
import org.apache.zeppelin.notebook.Notebook;
import org.apache.zeppelin.notebook.Paragraph;
import org.apache.zeppelin.notebook.repo.NotebookRepoSync;
import org.apache.zeppelin.scheduler.Job;
import org.apache.zeppelin.scheduler.Job.Status;
import org.apache.zeppelin.scheduler.JobListener;
@ -149,6 +146,9 @@ public class NotebookRepoSyncTest implements JobListenerFactory{
/* create note */
Note note = notebookSync.createNote();
Paragraph p1 = note.addParagraph();
Map config = p1.getConfig();
config.put("enabled", true);
p1.setConfig(config);
p1.setText("hello world");
/* new paragraph exists in note instance */