This commit is contained in:
astroshim 2016-10-11 09:05:39 +09:00
commit e8e0c179b1
102 changed files with 7137 additions and 4874 deletions

View file

@ -44,7 +44,7 @@ matrix:
# Test all modules with scala 2.10
- jdk: "oraclejdk7"
env: SCALA_VER="2.10" SPARK_VER="1.6.1" HADOOP_VER="2.3" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.3 -Ppyspark -Psparkr -Pscalding -Pexamples -Pscala-2.10" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
env: SCALA_VER="2.10" SPARK_VER="1.6.1" HADOOP_VER="2.3" PROFILE="-Pspark-1.6 -Pr -Phadoop-2.3 -Ppyspark -Psparkr -Pscalding -Pbeam -Pexamples -Pscala-2.10" BUILD_FLAG="package -Pbuild-distr -DskipRat" TEST_FLAG="verify -Pusing-packaged-distr -DskipRat" TEST_PROJECTS=""
# Test all modules with scala 2.11
- jdk: "oraclejdk7"

View file

@ -34,9 +34,6 @@ import org.apache.zeppelin.scheduler.SchedulerFactory;
*
*/
public class AngularInterpreter extends Interpreter {
static {
Interpreter.register("angular", AngularInterpreter.class.getName());
}
public AngularInterpreter(Properties property) {
super(property);

View file

@ -0,0 +1,10 @@
[
{
"group": "angular",
"name": "angular",
"className": "org.apache.zeppelin.angular.AngularInterpreter",
"properties": {
}
}
]

25
beam/README.md Normal file
View file

@ -0,0 +1,25 @@
# Overview
Beam interpreter for Apache Zeppelin
# Architecture
Current interpreter implementation supports the static repl. It compiles the code in memory, execute it and redirect the output to zeppelin.
## Building the Beam Interpreter
You have to first build the Beam interpreter by enable the **beam** profile as follows:
```
mvn clean package -Pbeam -DskipTests
```
### Notice
- Flink runner comes with binary compiled for scala 2.10. So, currently we support only Scala 2.10
### Technical overview
* Upon starting an interpreter, an instance of `JavaCompiler` is created.
* When the user runs commands with beam, the `JavaParser` go through the code to get a class that contains the main method.
* Then it replaces the class name with random class name to avoid overriding while compilation. it creates new out & err stream to get the data in new stream instead of the console, to redirect output to zeppelin.
* If there is any error during compilation, it can catch and redirect to zeppelin.

320
beam/pom.xml Normal file
View file

@ -0,0 +1,320 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Licensed to the Apache Software Foundation (ASF) under one or more
~ contributor license agreements. See the NOTICE file distributed with
~ this work for additional information regarding copyright ownership.
~ The ASF licenses this file to You under the Apache License, Version 2.0
~ (the "License"); you may not use this file except in compliance with
~ the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>zeppelin</artifactId>
<groupId>org.apache.zeppelin</groupId>
<version>0.7.0-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<groupId>org.apache.zeppelin</groupId>
<artifactId>zeppelin-beam</artifactId>
<packaging>jar</packaging>
<version>0.7.0-SNAPSHOT</version>
<name>Zeppelin: Beam interpreter</name>
<properties>
<beam.hadoop.version>2.3.0</beam.hadoop.version>
<beam.spark.version>1.6.2</beam.spark.version>
<beam.beam.version>0.2.0-incubating</beam.beam.version>
</properties>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.1.Final</version>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.10</artifactId>
<version>${beam.spark.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>netty-all</artifactId>
<groupId>io.netty</groupId>
</exclusion>
<exclusion>
<artifactId>akka-actor_2.10</artifactId>
<groupId>org.spark-project.akka</groupId>
</exclusion>
<exclusion>
<artifactId>akka-remote_2.10</artifactId>
<groupId>org.spark-project.akka</groupId>
</exclusion>
<exclusion>
<artifactId>akka-slf4j_2.10</artifactId>
<groupId>org.spark-project.akka</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.spark</groupId>
<artifactId>spark-streaming_2.10</artifactId>
<version>${beam.spark.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-core</artifactId>
<version>${beam.hadoop.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-common</artifactId>
<version>${beam.hadoop.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-hdfs</artifactId>
<version>${beam.hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-client</artifactId>
<version>${beam.hadoop.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-annotations</artifactId>
<version>${beam.hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-yarn-common</artifactId>
<version>${beam.hadoop.version}</version>
</dependency>
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-mapreduce-client-common</artifactId>
<version>${beam.hadoop.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.thoughtworks.qdox</groupId>
<artifactId>qdox</artifactId>
<version>2.0-M3</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-parent</artifactId>
<version>${beam.beam.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-core-java</artifactId>
<version>${beam.beam.version}</version>
<exclusions>
<exclusion>
<artifactId>google-http-client-jackson2</artifactId>
<groupId>com.google.http-client</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-direct-java</artifactId>
<version>${beam.beam.version}</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-flink_2.10</artifactId>
<version>${beam.beam.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
<exclusion>
<artifactId>netty-all</artifactId>
<groupId>io.netty</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-flink_2.10-examples</artifactId>
<version>${beam.beam.version}</version>
<exclusions>
<exclusion>
<artifactId>slf4j-log4j12</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-google-cloud-dataflow-java</artifactId>
<version>${beam.beam.version}</version>
<exclusions>
<exclusion>
<artifactId>google-http-client-jackson2</artifactId>
<groupId>com.google.http-client</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.beam</groupId>
<artifactId>beam-runners-spark</artifactId>
<version>${beam.beam.version}</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>zeppelin-interpreter</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<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>
<executions>
<execution>
<id>enforce</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/../../interpreter/beam</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
</configuration>
</execution>
<execution>
<id>copy-artifact</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/../../interpreter/beam</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
<artifactItems>
<artifactItem>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<type>${project.packaging}</type>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -0,0 +1,99 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.beam;
import java.io.File;
import java.util.Collections;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.apache.zeppelin.interpreter.thrift.InterpreterCompletion;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Beam interpreter
*
*/
public class BeamInterpreter extends Interpreter {
Logger logger = LoggerFactory.getLogger(BeamInterpreter.class);
public BeamInterpreter(Properties property) {
super(property);
}
@Override
public void open() {
}
@Override
public void close() {
File dir = new File(".");
// delete all .class files created while compilation process
for (int i = 0; i < dir.list().length; i++) {
File f = dir.listFiles()[i];
if (f.getAbsolutePath().endsWith(".class")) {
f.delete();
}
}
}
@Override
public InterpreterResult interpret(String code, InterpreterContext context) {
// choosing new name to class containing Main method
String generatedClassName = "C" + UUID.randomUUID().toString().replace("-", "");
try {
String res = StaticRepl.execute(generatedClassName, code);
return new InterpreterResult(InterpreterResult.Code.SUCCESS, res);
} catch (Exception e) {
logger.error("Exception in Interpreter while interpret", e);
return new InterpreterResult(InterpreterResult.Code.ERROR, e.getMessage());
}
}
@Override
public void cancel(InterpreterContext context) {
}
@Override
public FormType getFormType() {
return FormType.SIMPLE;
}
@Override
public int getProgress(InterpreterContext context) {
return 0;
}
@Override
public List<InterpreterCompletion> completion(String buf, int cursor) {
return Collections.emptyList();
}
}

View file

@ -0,0 +1,185 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.beam;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.SimpleJavaFileObject;
import javax.tools.ToolProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import com.thoughtworks.qdox.model.JavaSource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.List;
/**
*
* StaticRepl for compling the java code in memory
*
*/
public class StaticRepl {
static Logger logger = LoggerFactory.getLogger(StaticRepl.class);
public static String execute(String generatedClassName, String code) throws Exception {
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
// Java parasing
JavaProjectBuilder builder = new JavaProjectBuilder();
JavaSource src = builder.addSource(new StringReader(code));
// get all classes in code (paragraph)
List<JavaClass> classes = src.getClasses();
String mainClassName = null;
// Searching for class containing Main method
for (int i = 0; i < classes.size(); i++) {
boolean hasMain = false;
for (int j = 0; j < classes.get(i).getMethods().size(); j++) {
if (classes.get(i).getMethods().get(j).getName().equals("main") && classes.get(i)
.getMethods().get(j).isStatic()) {
mainClassName = classes.get(i).getName();
hasMain = true;
break;
}
}
if (hasMain == true) {
break;
}
}
// if there isn't Main method, will retuen error
if (mainClassName == null) {
logger.error("Exception for Main method", "There isn't any class "
+ "containing static main method.");
throw new Exception("There isn't any class containing static main method.");
}
// replace name of class containing Main method with generated name
code = code.replace(mainClassName, generatedClassName);
JavaFileObject file = new JavaSourceFromString(generatedClassName, code.toString());
Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(file);
ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
// Creating new stream to get the output data
PrintStream newOut = new PrintStream(baosOut);
PrintStream newErr = new PrintStream(baosErr);
// Save the old System.out!
PrintStream oldOut = System.out;
PrintStream oldErr = System.err;
// Tell Java to use your special stream
System.setOut(newOut);
System.setErr(newErr);
CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits);
// executing the compilation process
boolean success = task.call();
// if success is false will get error
if (!success) {
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
if (diagnostic.getLineNumber() == -1) {
continue;
}
System.err.println("line " + diagnostic.getLineNumber() + " : "
+ diagnostic.getMessage(null));
}
System.out.flush();
System.err.flush();
System.setOut(oldOut);
System.setErr(oldErr);
logger.error("Exception in Interpreter while compilation", baosErr.toString());
throw new Exception(baosErr.toString());
} else {
try {
// creating new class loader
URLClassLoader classLoader = URLClassLoader.newInstance(new URL[] { new File("").toURI()
.toURL() });
// execute the Main method
Class.forName(generatedClassName, true, classLoader)
.getDeclaredMethod("main", new Class[] { String[].class })
.invoke(null, new Object[] { null });
System.out.flush();
System.err.flush();
// set the stream to old stream
System.setOut(oldOut);
System.setErr(oldErr);
return baosOut.toString();
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException
| InvocationTargetException e) {
logger.error("Exception in Interpreter while execution", e);
System.err.println(e);
e.printStackTrace(newErr);
throw new Exception(baosErr.toString(), e);
} finally {
System.out.flush();
System.err.flush();
System.setOut(oldOut);
System.setErr(oldErr);
}
}
}
}
class JavaSourceFromString extends SimpleJavaFileObject {
final String code;
JavaSourceFromString(String name, String code) {
super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
this.code = code;
}
@Override
public CharSequence getCharContent(boolean ignoreEncodingErrors) {
return code;
}
}

View file

@ -0,0 +1,11 @@
[
{
"group": "beam",
"name": "beam",
"className": "org.apache.zeppelin.beam.BeamInterpreter",
"defaultInterpreter": true,
"properties": {
}
}
]

View file

@ -0,0 +1,100 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.zeppelin.beam;
import static org.junit.Assert.assertEquals;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Properties;
import org.apache.zeppelin.interpreter.InterpreterContext;
import org.apache.zeppelin.interpreter.InterpreterResult;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
/**
*
* BeamInterpreterTest
*
*/
public class BeamInterpreterTest {
private static BeamInterpreter beam;
private static InterpreterContext context;
@BeforeClass
public static void setUp() {
Properties p = new Properties();
beam = new BeamInterpreter(p);
beam.open();
context = new InterpreterContext(null, null, null, null, null, null, null, null, null, null,
null);
}
@AfterClass
public static void tearDown() {
beam.close();
}
@Test
public void testStaticRepl() {
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
out.println("public class HelloWorld {");
out.println(" public static void main(String args[]) {");
out.println(" System.out.println(\"This is in another java file\");");
out.println(" }");
out.println("}");
out.close();
InterpreterResult res = beam.interpret(writer.toString(), context);
assertEquals(InterpreterResult.Code.SUCCESS, res.code());
}
@Test
public void testStaticReplWithoutMain() {
StringBuffer sourceCode = new StringBuffer();
sourceCode.append("package org.mdkt;\n");
sourceCode.append("public class HelloClass {\n");
sourceCode.append(" public String hello() { return \"hello\"; }");
sourceCode.append("}");
InterpreterResult res = beam.interpret(sourceCode.toString(), context);
assertEquals(InterpreterResult.Code.ERROR, res.code());
}
@Test
public void testStaticReplWithSyntaxError() {
StringWriter writer = new StringWriter();
PrintWriter out = new PrintWriter(writer);
out.println("public class HelloWorld {");
out.println(" public static void main(String args[]) {");
out.println(" System.out.prin(\"This is in another java file\");");
out.println(" }");
out.println("}");
out.close();
InterpreterResult res = beam.interpret(writer.toString(), context);
assertEquals(InterpreterResult.Code.ERROR, res.code());
}
}

View file

@ -151,111 +151,6 @@ public class CassandraInterpreter extends Interpreter {
super(properties);
}
static {
LOGGER.info("Bootstrapping Cassandra Interpreter");
Interpreter.register("cassandra", "cassandra", CassandraInterpreter.class.getName(),
new InterpreterPropertyBuilder()
.add(CASSANDRA_HOSTS, DEFAULT_HOST,
"Comma separated Cassandra hosts (DNS name or " +
"IP address). Default = localhost. Ex: '192.168.0.12,node2,node3'")
.add(CASSANDRA_PORT, DEFAULT_PORT, "Cassandra native port. Default = 9042")
.add(CASSANDRA_PROTOCOL_VERSION, DEFAULT_PROTOCOL_VERSION,
"Cassandra protocol version. Default = 4")
.add(CASSANDRA_CLUSTER_NAME, DEFAULT_CLUSTER, "Cassandra cluster name. " +
"Default = 'Test Cluster'")
.add(CASSANDRA_KEYSPACE_NAME, DEFAULT_KEYSPACE, "Cassandra keyspace name. " +
"Default = 'system'")
.add(CASSANDRA_COMPRESSION_PROTOCOL, DEFAULT_COMPRESSION,
"Cassandra compression protocol. " +
"Available values: NONE, SNAPPY, LZ4. Default = NONE")
.add(CASSANDRA_CREDENTIALS_USERNAME, DEFAULT_CREDENTIAL,
"Cassandra credentials username. " +
"Default = 'none'")
.add(CASSANDRA_CREDENTIALS_PASSWORD, DEFAULT_CREDENTIAL,
"Cassandra credentials password. " +
"Default = 'none'")
.add(CASSANDRA_LOAD_BALANCING_POLICY, DEFAULT_POLICY, "Cassandra Load Balancing Policy. " +
"Default = new TokenAwarePolicy(new DCAwareRoundRobinPolicy())")
.add(CASSANDRA_RETRY_POLICY, DEFAULT_POLICY, "Cassandra Retry Policy. " +
"Default = DefaultRetryPolicy.INSTANCE")
.add(CASSANDRA_RECONNECTION_POLICY, DEFAULT_POLICY, "Cassandra Reconnection Policy. " +
"Default = new ExponentialReconnectionPolicy(1000, 10 * 60 * 1000)")
.add(CASSANDRA_SPECULATIVE_EXECUTION_POLICY, DEFAULT_POLICY,
"Cassandra Speculative Execution Policy. " +
"Default = NoSpeculativeExecutionPolicy.INSTANCE")
.add(CASSANDRA_INTERPRETER_PARALLELISM, DEFAULT_PARALLELISM,
"Cassandra interpreter parallelism" +
".Default = 10")
.add(CASSANDRA_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS,
DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS + ""
, "Cassandra max schema agreement wait in second" +
".Default = ProtocolOptions.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS")
.add(CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_LOCAL,
DEFAULT_NEW_CONNECTION_THRESHOLD_LOCAL,
"Cassandra new connection threshold local. " +
"Protocol V2 and below default = 100" +
"Protocol V3 and above default = 800")
.add(CASSANDRA_POOLING_NEW_CONNECTION_THRESHOLD_REMOTE,
DEFAULT_NEW_CONNECTION_THRESHOLD_REMOTE,
"Cassandra new connection threshold remove. " +
"Protocol V2 and below default = 100" +
"Protocol V3 and above default = 200")
.add(CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_LOCAL,
DEFAULT_CORE_CONNECTION_PER_HOST_LOCAL,
"Cassandra core connection per host local. " +
"Protocol V2 and below default = 2" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_CORE_CONNECTION_PER_HOST_REMOTE,
DEFAULT_CORE_CONNECTION_PER_HOST_REMOTE,
"Cassandra core connection per host remove. " +
"Protocol V2 and below default = 1" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_LOCAL,
DEFAULT_MAX_CONNECTION_PER_HOST_LOCAL,
"Cassandra max connection per host local. " +
"Protocol V2 and below default = 8" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_MAX_CONNECTION_PER_HOST_REMOTE,
DEFAULT_MAX_CONNECTION_PER_HOST_REMOTE,
"Cassandra max connection per host remote. " +
"Protocol V2 and below default = 2" +
"Protocol V3 and above default = 1")
.add(CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_LOCAL,
DEFAULT_MAX_REQUEST_PER_CONNECTION_LOCAL,
"Cassandra max request per connection local. " +
"Protocol V2 and below default = 128" +
"Protocol V3 and above default = 1024")
.add(CASSANDRA_POOLING_MAX_REQUESTS_PER_CONNECTION_REMOTE,
DEFAULT_MAX_REQUEST_PER_CONNECTION_REMOTE,
"Cassandra max request per connection remote. " +
"Protocol V2 and below default = 128" +
"Protocol V3 and above default = 256")
.add(CASSANDRA_POOLING_IDLE_TIMEOUT_SECONDS, DEFAULT_IDLE_TIMEOUT,
"Cassandra idle time out in seconds. Default = 120")
.add(CASSANDRA_POOLING_POOL_TIMEOUT_MILLIS, DEFAULT_POOL_TIMEOUT,
"Cassandra pool time out in millisecs. Default = 5000")
.add(CASSANDRA_POOLING_HEARTBEAT_INTERVAL_SECONDS, DEFAULT_HEARTBEAT_INTERVAL,
"Cassandra pool heartbeat interval in secs. Default = 30")
.add(CASSANDRA_QUERY_DEFAULT_CONSISTENCY, DEFAULT_CONSISTENCY,
"Cassandra query default consistency level. Default = ONE")
.add(CASSANDRA_QUERY_DEFAULT_SERIAL_CONSISTENCY, DEFAULT_SERIAL_CONSISTENCY,
"Cassandra query default serial consistency level. Default = SERIAL")
.add(CASSANDRA_QUERY_DEFAULT_FETCH_SIZE, DEFAULT_FETCH_SIZE,
"Cassandra query default fetch size. Default = 5000")
.add(CASSANDRA_SOCKET_CONNECTION_TIMEOUT_MILLIS, DEFAULT_CONNECTION_TIMEOUT,
"Cassandra socket default connection timeout in millisecs. Default = 5000")
.add(CASSANDRA_SOCKET_READ_TIMEOUT_MILLIS, DEFAULT_READ_TIMEOUT,
"Cassandra socket read timeout in millisecs. Default = 12000")
.add(CASSANDRA_SOCKET_TCP_NO_DELAY, DEFAULT_TCP_NO_DELAY,
"Cassandra socket TCP no delay. Default = true")
.build());
}
@Override
public void open() {

View file

@ -0,0 +1,195 @@
[
{
"group": "cassandra",
"name": "cassandra",
"className": "org.apache.zeppelin.cassandra.CassandraInterpreter",
"properties": {
"cassandra.hosts": {
"envName": null,
"propertyName": "cassandra.hosts",
"defaultValue": "localhost",
"description": "Comma separated Cassandra hosts (DNS name or IP address). Default = localhost. Ex: '192.168.0.12,node2,node3'"
},
"cassandra.native.port": {
"envName": null,
"propertyName": "cassandra.native.port",
"defaultValue": "9042",
"description": "Cassandra native port. Default = 9042"
},
"cassandra.protocol.version": {
"envName": null,
"propertyName": "cassandra.protocol.version",
"defaultValue": "4",
"description": "Cassandra protocol version. Default = 4"
},
"cassandra.cluster": {
"envName": null,
"propertyName": "cassandra.cluster",
"defaultValue": "Test Cluster",
"description": "Cassandra cluster name. Default = 'Test Cluster'"
},
"cassandra.keyspace": {
"envName": null,
"propertyName": "cassandra.keyspace",
"defaultValue": "system",
"description": "Cassandra keyspace name. Default = 'system'"
},
"cassandra.compression.protocol": {
"envName": null,
"propertyName": "cassandra.compression.protocol",
"defaultValue": "NONE",
"description": "Cassandra compression protocol. Available values: NONE, SNAPPY, LZ4. Default = NONE"
},
"cassandra.credentials.username": {
"envName": null,
"propertyName": "cassandra.credentials.username",
"defaultValue": "none",
"description": "Cassandra credentials username. Default = 'none'"
},
"cassandra.credentials.password": {
"envName": null,
"propertyName": "cassandra.credentials.password",
"defaultValue": "none",
"description": "Cassandra credentials password. Default = 'none'"
},
"cassandra.load.balancing.policy": {
"envName": null,
"propertyName": "cassandra.load.balancing.policy",
"defaultValue": "DEFAULT",
"description": "Cassandra Load Balancing Policy. Default = new TokenAwarePolicy(new DCAwareRoundRobinPolicy())"
},
"cassandra.retry.policy": {
"envName": null,
"propertyName": "cassandra.retry.policy",
"defaultValue": "DEFAULT",
"description": "Cassandra Retry Policy. Default = DefaultRetryPolicy.INSTANCE"
},
"cassandra.reconnection.policy": {
"envName": null,
"propertyName": "cassandra.reconnection.policy",
"defaultValue": "DEFAULT",
"description": "Cassandra Reconnection Policy. Default = new ExponentialReconnectionPolicy(1000, 10 * 60 * 1000)"
},
"cassandra.speculative.execution.policy": {
"envName": null,
"propertyName": "cassandra.speculative.execution.policy",
"defaultValue": "DEFAULT",
"description": "Cassandra Speculative Execution Policy. Default = NoSpeculativeExecutionPolicy.INSTANCE"
},
"cassandra.interpreter.parallelism": {
"envName": null,
"propertyName": "cassandra.interpreter.parallelism",
"defaultValue": "10",
"description": "Cassandra interpreter parallelism.Default = 10"
},
"cassandra.max.schema.agreement.wait.second": {
"envName": null,
"propertyName": "cassandra.max.schema.agreement.wait.second",
"defaultValue": "10",
"description": "Cassandra max schema agreement wait in second.Default = ProtocolOptions.DEFAULT_MAX_SCHEMA_AGREEMENT_WAIT_SECONDS"
},
"cassandra.pooling.new.connection.threshold.local": {
"envName": null,
"propertyName": "cassandra.pooling.new.connection.threshold.local",
"defaultValue": "100",
"description": "Cassandra new connection threshold local. Protocol V2 and below default = 100 Protocol V3 and above default = 800"
},
"cassandra.pooling.new.connection.threshold.remote": {
"envName": null,
"propertyName": "cassandra.pooling.new.connection.threshold.remote",
"defaultValue": "100",
"description": "Cassandra new connection threshold remove. Protocol V2 and below default = 100 Protocol V3 and above default = 200"
},
"cassandra.pooling.core.connection.per.host.local": {
"envName": null,
"propertyName": "cassandra.pooling.core.connection.per.host.local",
"defaultValue": "2",
"description": "Cassandra core connection per host local. Protocol V2 and below default = 2 Protocol V3 and above default = 1"
},
"cassandra.pooling.core.connection.per.host.remote": {
"envName": null,
"propertyName": "cassandra.pooling.core.connection.per.host.remote",
"defaultValue": "1",
"description": "Cassandra core connection per host remove. Protocol V2 and below default = 1 Protocol V3 and above default = 1"
},
"cassandra.pooling.max.connection.per.host.local": {
"envName": null,
"propertyName": "cassandra.pooling.max.connection.per.host.local",
"defaultValue": "8",
"description": "Cassandra max connection per host local. Protocol V2 and below default = 8 Protocol V3 and above default = 1"
},
"cassandra.pooling.max.connection.per.host.remote": {
"envName": null,
"propertyName": "cassandra.pooling.max.connection.per.host.remote",
"defaultValue": "2",
"description": "Cassandra max connection per host remote. Protocol V2 and below default = 2 Protocol V3 and above default = 1"
},
"cassandra.pooling.max.request.per.connection.local": {
"envName": null,
"propertyName": "cassandra.pooling.max.request.per.connection.local",
"defaultValue": "1024",
"description": "Cassandra max request per connection local. Protocol V2 and below default = 128 Protocol V3 and above default = 1024"
},
"cassandra.pooling.max.request.per.connection.remote": {
"envName": null,
"propertyName": "cassandra.pooling.max.request.per.connection.remote",
"defaultValue": "256",
"description": "Cassandra max request per connection remote. Protocol V2 and below default = 128 Protocol V3 and above default = 256"
},
"cassandra.pooling.idle.timeout.seconds": {
"envName": null,
"propertyName": "cassandra.pooling.idle.timeout.seconds",
"defaultValue": "120",
"description": "Cassandra idle time out in seconds. Default = 120"
},
"cassandra.pooling.pool.timeout.millisecs": {
"envName": null,
"propertyName": "cassandra.pooling.pool.timeout.millisecs",
"defaultValue": "5000",
"description": "Cassandra pool time out in millisecs. Default = 5000"
},
"cassandra.pooling.heartbeat.interval.seconds": {
"envName": null,
"propertyName": "cassandra.pooling.heartbeat.interval.seconds",
"defaultValue": "30",
"description": "Cassandra pool heartbeat interval in secs. Default = 30"
},
"cassandra.query.default.consistency": {
"envName": null,
"propertyName": "cassandra.query.default.consistency",
"defaultValue": "ONE",
"description": "Cassandra query default consistency level. Default = ONE"
},
"cassandra.query.default.serial.consistency": {
"envName": null,
"propertyName": "cassandra.query.default.serial.consistency",
"defaultValue": "SERIAL",
"description": "Cassandra query default serial consistency level. Default = SERIAL"
},
"cassandra.query.default.fetchSize": {
"envName": null,
"propertyName": "cassandra.query.default.fetchSize",
"defaultValue": "5000",
"description": "Cassandra query default fetch size. Default = 5000"
},
"cassandra.socket.connection.timeout.millisecs": {
"envName": null,
"propertyName": "cassandra.socket.connection.timeout.millisecs",
"defaultValue": "5000",
"description": "Cassandra socket default connection timeout in millisecs. Default = 5000"
},
"cassandra.socket.read.timeout.millisecs": {
"envName": null,
"propertyName": "cassandra.socket.read.timeout.millisecs",
"defaultValue": "12000",
"description": "Cassandra socket read timeout in millisecs. Default = 12000"
},
"cassandra.socket.tcp.no_delay": {
"envName": null,
"propertyName": "cassandra.socket.tcp.no_delay",
"defaultValue": "true",
"description": "Cassandra socket TCP no delay. Default = true"
}
}
}
]

View file

@ -19,6 +19,7 @@
alluxio org.apache.zeppelin:zeppelin-alluxio:0.6.1 Alluxio interpreter
angular org.apache.zeppelin:zeppelin-angular:0.6.1 HTML and AngularJS view rendering
beam org.apache.zeppelin:zeppelin-beam:0.6.1 Beam interpreter
bigquery org.apache.zeppelin:zeppelin-bigquery:0.6.1 BigQuery interpreter
cassandra org.apache.zeppelin:zeppelin-cassandra_2.11:0.6.1 Cassandra interpreter built with Scala 2.11
elasticsearch org.apache.zeppelin:zeppelin-elasticsearch:0.6.1 Elasticsearch interpreter

View file

@ -22,6 +22,7 @@
# export ZEPPELIN_MEM # Zeppelin jvm mem options Default -Xmx1024m -XX:MaxPermSize=512m
# export ZEPPELIN_INTP_MEM # zeppelin interpreter process jvm mem options.
# export ZEPPELIN_INTP_JAVA_OPTS # zeppelin interpreter process jvm options.
# export ZEPPELIN_SSL_PORT # ssl port (used when ssl environment variable is set to true)
# export ZEPPELIN_LOG_DIR # Where log files are stored. PWD by default.
# export ZEPPELIN_PID_DIR # The pid files are stored. ${ZEPPELIN_HOME}/run by default.

View file

@ -31,6 +31,12 @@
<description>Server port.</description>
</property>
<property>
<name>zeppelin.server.ssl.port</name>
<value>8443</value>
<description>Server ssl port. (used when ssl property is set to true)</description>
</property>
<property>
<name>zeppelin.server.context.path</name>
<value>/</value>
@ -184,13 +190,13 @@
<property>
<name>zeppelin.interpreters</name>
<value>org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.rinterpreter.RRepl,org.apache.zeppelin.rinterpreter.KnitR,org.apache.zeppelin.spark.SparkRInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.file.HDFSFileInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,,org.apache.zeppelin.python.PythonInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.postgresql.PostgreSqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.alluxio.AlluxioInterpreter,org.apache.zeppelin.hbase.HbaseInterpreter,org.apache.zeppelin.livy.LivySparkInterpreter,org.apache.zeppelin.livy.LivyPySparkInterpreter,org.apache.zeppelin.livy.LivySparkRInterpreter,org.apache.zeppelin.livy.LivySparkSQLInterpreter,org.apache.zeppelin.bigquery.BigQueryInterpreter</value>
<value>org.apache.zeppelin.spark.SparkInterpreter,org.apache.zeppelin.spark.PySparkInterpreter,org.apache.zeppelin.rinterpreter.RRepl,org.apache.zeppelin.rinterpreter.KnitR,org.apache.zeppelin.spark.SparkRInterpreter,org.apache.zeppelin.spark.SparkSqlInterpreter,org.apache.zeppelin.spark.DepInterpreter,org.apache.zeppelin.markdown.Markdown,org.apache.zeppelin.angular.AngularInterpreter,org.apache.zeppelin.shell.ShellInterpreter,org.apache.zeppelin.file.HDFSFileInterpreter,org.apache.zeppelin.flink.FlinkInterpreter,,org.apache.zeppelin.python.PythonInterpreter,org.apache.zeppelin.lens.LensInterpreter,org.apache.zeppelin.ignite.IgniteInterpreter,org.apache.zeppelin.ignite.IgniteSqlInterpreter,org.apache.zeppelin.cassandra.CassandraInterpreter,org.apache.zeppelin.geode.GeodeOqlInterpreter,org.apache.zeppelin.postgresql.PostgreSqlInterpreter,org.apache.zeppelin.jdbc.JDBCInterpreter,org.apache.zeppelin.kylin.KylinInterpreter,org.apache.zeppelin.elasticsearch.ElasticsearchInterpreter,org.apache.zeppelin.scalding.ScaldingInterpreter,org.apache.zeppelin.alluxio.AlluxioInterpreter,org.apache.zeppelin.hbase.HbaseInterpreter,org.apache.zeppelin.livy.LivySparkInterpreter,org.apache.zeppelin.livy.LivyPySparkInterpreter,org.apache.zeppelin.livy.LivySparkRInterpreter,org.apache.zeppelin.livy.LivySparkSQLInterpreter,org.apache.zeppelin.bigquery.BigQueryInterpreter,org.apache.zeppelin.beam.BeamInterpreter</value>
<description>Comma separated interpreter configurations. First interpreter become a default</description>
</property>
<property>
<name>zeppelin.interpreter.group.order</name>
<value>spark,md,angular,sh,livy,alluxio,file,psql,flink,python,ignite,lens,cassandra,geode,kylin,elasticsearch,scalding,jdbc,hbase,bigquery</value>
<value>spark,md,angular,sh,livy,alluxio,file,psql,flink,python,ignite,lens,cassandra,geode,kylin,elasticsearch,scalding,jdbc,hbase,bigquery,beam</value>
<description></description>
</property>

View file

@ -33,6 +33,7 @@
<li role="separator" class="divider"></li>
<li class="title"><span><b>More</b><span></li>
<li><a href="{{BASE_PATH}}/install/upgrade.html">Upgrade Zeppelin Version</a></li>
<li><a href="{{BASE_PATH}}/quickstart/install_with_flink_and_spark_cluster.html">Install Zeppelin with Flink and Spark Clusters Tutorial</a></li>
</ul>
</li>
<li>
@ -47,6 +48,7 @@
<li role="separator" class="divider"></li>
<li class="title"><span><b>Available Interpreters</b><span></li>
<li><a href="{{BASE_PATH}}/interpreter/alluxio.html">Alluxio</a></li>
<li><a href="{{BASE_PATH}}/interpreter/beam.html">Beam</a></li>
<li><a href="{{BASE_PATH}}/interpreter/bigquery.html">BigQuery</a></li>
<li><a href="{{BASE_PATH}}/interpreter/cassandra.html">Cassandra</a></li>
<li><a href="{{BASE_PATH}}/interpreter/elasticsearch.html">Elasticsearch</a></li>
@ -107,6 +109,7 @@
<li><a href="{{BASE_PATH}}/install/spark_cluster_mode.html#spark-standalone-mode">Zeppelin on Spark Cluster Mode (Standalone)</a></li>
<li><a href="{{BASE_PATH}}/install/spark_cluster_mode.html#spark-on-yarn-mode">Zeppelin on Spark Cluster Mode (YARN)</a></li>
<li><a href="{{BASE_PATH}}/install/spark_cluster_mode.html#spark-on-mesos-mode">Zeppelin on Spark Cluster Mode (Mesos)</a></li>
<li><a href="{{BASE_PATH}}/install/cdh.html">Zeppelin on CDH</a></li>
<li role="separator" class="divider"></li>
<li class="title"><span><b>Contibute</b><span></li>
<li><a href="{{BASE_PATH}}/development/writingzeppelininterpreter.html">Writing Zeppelin Interpreter</a></li>

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 352 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -1,6 +1,6 @@
---
layout: nil
title : Atom Feed
title :
---
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

View file

@ -172,6 +172,7 @@ Join to our [Mailing list](https://zeppelin.apache.org/community.html) and repor
* [Zeppelin on Spark Cluster Mode (Standalone via Docker)](./install/spark_cluster_mode.html#spark-standalone-mode)
* [Zeppelin on Spark Cluster Mode (YARN via Docker)](./install/spark_cluster_mode.html#spark-on-yarn-mode)
* [Zeppelin on Spark Cluster Mode (Mesos via Docker)](./install/spark_cluster_mode.html#spark-on-mesos-mode)
* [Zeppelin on CDH (via Docker)](./install/cdh.html)
* Contribute
* [Writing Zeppelin Interpreter](./development/writingzeppelininterpreter.html)
* [Writing Zeppelin Application (Experimental)](./development/writingzeppelinapplication.html)

100
docs/install/cdh.md Normal file
View file

@ -0,0 +1,100 @@
---
layout: page
title: "Apache Zeppelin on CDH"
description: "This document will guide you how you can build and configure the environment on CDH with Apache Zeppelin using docker scripts."
group: install
---
<!--
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.
-->
{% include JB/setup %}
# Apache Zeppelin on CDH
<div id="toc"></div>
### 1. Import Cloudera QuickStart Docker image
>[Cloudera](http://www.cloudera.com/) has officially provided CDH Docker Hub in their own container. Please check [this guide page](http://www.cloudera.com/documentation/enterprise/latest/topics/quickstart_docker_container.html#cloudera_docker_container) for more information.
You can import the Docker image by pulling it from Cloudera Docker Hub.
```
docker pull cloudera/quickstart:latest
```
### 2. Run docker
```
docker run -it \
-p 80:80 \
-p 4040:4040 \
-p 8020:8020 \
-p 8022:8022 \
-p 8030:8030 \
-p 8032:8032 \
-p 8033:8033 \
-p 8040:8040 \
-p 8042:8042 \
-p 8088:8088 \
-p 8480:8480 \
-p 8485:8485 \
-p 8888:8888 \
-p 9083:9083 \
-p 10020:10020 \
-p 10033:10033 \
-p 18088:18088 \
-p 19888:19888 \
-p 25000:25000 \
-p 25010:25010 \
-p 25020:25020 \
-p 50010:50010 \
-p 50020:50020 \
-p 50070:50070 \
-p 50075:50075 \
-h quickstart.cloudera --privileged=true \
agitated_payne_backup /usr/bin/docker-quickstart;
```
### 3. Verify running CDH
To verify the application is running well, check the web UI for HDFS on `http://<hostname>:50070/` and YARN on `http://<hostname>:8088/cluster`.
### 4. Configure Spark interpreter in Zeppelin
Set following configurations to `conf/zeppelin-env.sh`.
```
export MASTER=yarn-client
export HADOOP_CONF_DIR=[your_hadoop_conf_path]
export SPARK_HOME=[your_spark_home_path]
```
`HADOOP_CONF_DIR`(Hadoop configuration path) is defined in `/scripts/docker/spark-cluster-managers/cdh/hdfs_conf`.
Don't forget to set Spark `master` as `yarn-client` in Zeppelin **Interpreters** setting page like below.
<img src="../assets/themes/zeppelin/img/docs-img/zeppelin_yarn_conf.png" />
### 5. Run Zeppelin with Spark interpreter
After running a single paragraph with Spark interpreter in Zeppelin,
<img src="../assets/themes/zeppelin/img/docs-img/zeppelin_with_cdh.png" />
<br/>
browse `http://<hostname>:8088/cluster/apps` to check Zeppelin application is running well or not.
<img src="../assets/themes/zeppelin/img/docs-img/cdh_yarn_applications.png" />

View file

@ -211,6 +211,12 @@ You can configure Apache Zeppelin with either **environment variables** in `conf
<td>8080</td>
<td>Zeppelin server port</td>
</tr>
<tr>
<td>ZEPPELIN_SSL_PORT</td>
<td>zeppelin.server.ssl.port</td>
<td>8443</td>
<td>Zeppelin Server ssl port (used when ssl environment/property is set to true)</td>
</tr>
<tr>
<td>ZEPPELIN_MEM</td>
<td>N/A</td>

View file

@ -51,3 +51,4 @@ So, copying `notebook` and `conf` directory should be enough.
- From 0.7, we don't use `ZEPPELIN_JAVA_OPTS` as default value of `ZEPPELIN_INTP_JAVA_OPTS` and also the same for `ZEPPELIN_MEM`/`ZEPPELIN_INTP_MEM`. If user want to configure the jvm opts of interpreter process, please set `ZEPPELIN_INTP_JAVA_OPTS` and `ZEPPELIN_INTP_MEM` explicitly.
- Mapping from `%jdbc(prefix)` to `%prefix` is no longer available. Instead, you can use %[interpreter alias] with multiple interpreter setttings on GUI.
- Usage of `ZEPPELIN_PORT` is not supported in ssl mode. Instead use `ZEPPELIN_SSL_PORT` to configure the ssl port. Value from `ZEPPELIN_PORT` is used only when `ZEPPELIN_SSL` is set to `false`.

124
docs/interpreter/beam.md Normal file
View file

@ -0,0 +1,124 @@
---
layout: page
title: Beam interpreter in Apache Zeppelin
description: Apache Beam is an open source, unified programming model that you can use to create a data processing pipeline.
group: interpreter
---
<!--
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.
-->
{% include JB/setup %}
# Beam interpreter for Apache Zeppelin
<div id="toc"></div>
## Overview
[Apache Beam](http://beam.incubator.apache.org) is an open source unified platform for data processing pipelines. A pipeline can be build using one of the Beam SDKs.
The execution of the pipeline is done by different Runners. Currently, Beam supports Apache Flink Runner, Apache Spark Runner, and Google Dataflow Runner.
## How to use
Basically, you can write normal Beam java code where you can determine the Runner. You should write the main method inside a class becuase the interpreter invoke this main to execute the pipeline. Unlike Zeppelin normal pattern, each paragraph is considered as a separate job, there isn't any relation to any other paragraph.
The following is a demonstration of a word count example with data represented in array of strings
But it can read data from files by replacing `Create.of(SENTENCES).withCoder(StringUtf8Coder.of())` with `TextIO.Read.from("path/to/filename.txt")`
```java
%beam
// most used imports
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.transforms.Create;
import java.io.Serializable;
import java.util.Arrays;
import java.util.List;
import java.util.ArrayList;
import org.apache.spark.api.java.*;
import org.apache.spark.api.java.function.Function;
import org.apache.spark.SparkConf;
import org.apache.spark.streaming.*;
import org.apache.spark.SparkContext;
import org.apache.beam.runners.direct.*;
import org.apache.beam.sdk.runners.*;
import org.apache.beam.sdk.options.*;
import org.apache.beam.runners.spark.*;
import org.apache.beam.runners.spark.io.ConsoleIO;
import org.apache.beam.runners.flink.*;
import org.apache.beam.runners.flink.examples.WordCount.Options;
import org.apache.beam.sdk.Pipeline;
import org.apache.beam.sdk.io.TextIO;
import org.apache.beam.sdk.options.PipelineOptionsFactory;
import org.apache.beam.sdk.transforms.Count;
import org.apache.beam.sdk.transforms.DoFn;
import org.apache.beam.sdk.transforms.MapElements;
import org.apache.beam.sdk.transforms.ParDo;
import org.apache.beam.sdk.transforms.SimpleFunction;
import org.apache.beam.sdk.values.KV;
import org.apache.beam.sdk.options.PipelineOptions;
public class MinimalWordCount {
static List<String> s = new ArrayList<>();
static final String[] SENTENCES_ARRAY = new String[] {
"Hadoop is the Elephant King!",
"A yellow and elegant thing.",
"He never forgets",
"Useful data, or lets",
"An extraneous element cling!",
"A wonderful king is Hadoop.",
"The elephant plays well with Sqoop.",
"But what helps him to thrive",
"Are Impala, and Hive,",
"And HDFS in the group.",
"Hadoop is an elegant fellow.",
"An elephant gentle and mellow.",
"He never gets mad,",
"Or does anything bad,",
"Because, at his core, he is yellow",
};
static final List<String> SENTENCES = Arrays.asList(SENTENCES_ARRAY);
public static void main(String[] args) {
Options options = PipelineOptionsFactory.create().as(Options.class);
options.setRunner(FlinkRunner.class);
Pipeline p = Pipeline.create(options);
p.apply(Create.of(SENTENCES).withCoder(StringUtf8Coder.of()))
.apply("ExtractWords", ParDo.of(new DoFn<String, String>() {
@Override
public void processElement(ProcessContext c) {
for (String word : c.element().split("[^a-zA-Z']+")) {
if (!word.isEmpty()) {
c.output(word);
}
}
}
}))
.apply(Count.<String> perElement())
.apply("FormatResults", ParDo.of(new DoFn<KV<String, Long>, String>() {
@Override
public void processElement(DoFn<KV<String, Long>, String>.ProcessContext arg0)
throws Exception {
s.add("\n" + arg0.element().getKey() + "\t" + arg0.element().getValue());
}
}));
p.run();
System.out.println("%table word\tcount");
for (int i = 0; i < s.size(); i++) {
System.out.print(s.get(i));
}
}
}
```

View file

@ -269,38 +269,76 @@ To develop this functionality use this [method](http://docs.oracle.com/javase/7/
</table>
### Phoenix
#### Properties
Phoenix supports `thick` and `thin` connection types:
- Thick client is faster, but must connect directly to ZooKeeper and HBase RegionServers.
- Thin client has fewer dependencies and connects through a [Phoenix Query Server](http://phoenix.apache.org/server.html) instance.
Use the appropriate `phoenix.driver` and `phoenix.url` for your connection type.
#### Properties:
<table class="table-configuration">
<tr>
<th>Name</th>
<th>Value</th>
<th>Description</th>
</tr>
<tr>
<td>phoenix.driver</td>
<td>org.apache.phoenix.jdbc.PhoenixDriver</td>
<td>'Thick Client', connects directly to Phoenix</td>
</tr>
<tr>
<td>phoenix.driver</td>
<td>org.apache.phoenix.queryserver.client.Driver</td>
<td>'Thin Client', connects via Phoenix Query Server</td>
</tr>
<tr>
<td>phoenix.url</td>
<td>jdbc:phoenix:localhost:2181:/hbase-unsecure</td>
<td>'Thick Client', connects directly to Phoenix</td>
</tr>
<tr>
<td>phoenix.url</td>
<td>jdbc:phoenix:thin:url=http://localhost:8765;serialization=PROTOBUF</td>
<td>'Thin Client', connects via Phoenix Query Server</td>
</tr>
<tr>
<td>phoenix.user</td>
<td>phoenix_user</td>
<td></td>
</tr>
<tr>
<td>phoenix.password</td>
<td>phoenix_password</td>
<td></td>
</tr>
</table>
#### Dependencies
#### Dependencies:
Include the dependency for your connection type (it should be only *one* of the following).
<table class="table-configuration">
<tr>
<th>Artifact</th>
<th>Excludes</th>
<th>Description</th>
</tr>
<tr>
<td>org.apache.phoenix:phoenix-core:4.4.0-HBase-1.0</td>
<td></td>
<td>'Thick Client', connects directly to Phoenix</td>
</tr>
<tr>
<td>org.apache.phoenix:phoenix-server-client:4.7.0-HBase-1.1</td>
<td></td>
<td>'Thin Client' for Phoenix 4.7, connects via Phoenix Query Server</td>
</tr>
<tr>
<td>org.apache.phoenix:phoenix-queryserver-client:4.8.0-HBase-1.2</td>
<td></td>
<td>'Thin Client' for Phoenix 4.8+, connects via Phoenix Query Server</td>
</tr>
</table>

View file

@ -68,6 +68,7 @@ When your code requires external library, instead of doing download/copy/restart
<li> If you need to resolve dependencies from other than central maven repository or
local ~/.m2 repository, hit <i class="fa fa-plus"></i> icon next to repository lists. </li>
<li> Fill out the form and click 'Add' button, then you will be able to see that new repository is added. </li>
<li> Optionally, if you are behind a corporate firewall, you can specify also all proxy settings so that Zeppelin can download the dependencies using the given credentials</li>
</ol>
</div>
</div>

View file

@ -0,0 +1,414 @@
---
layout: page
title: "Install Zeppelin with Flink and Spark in cluster mode"
description: "Tutorial is valid for Spark 1.6.x and Flink 1.1.2"
group: tutorial
---
<!--
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.
-->
This tutorial is extremely entry-level. It assumes no prior knowledge of Linux, git, or other tools. If you carefully type what I tell you when I tell you, you should be able to get Zeppelin running.
## Installing Zeppelin with Flink and Spark in cluster mode
This tutorial assumes the user has a machine (real or [virtual](https://www.virtualbox.org/wiki/Downloads) with a fresh, minimal installation of [Ubuntu 14.04.3 Server](http://www.ubuntu.com/download/server).
**Note:** On the size requirements of the Virtual Machine, some users reported trouble when using the default virtual machine sizes, specifically that the hard drive needed to be at least 16GB- other users did not have this issue.
There are many good tutorials on how to install Ubuntu Server on a virtual box, [here is one of them](http://ilearnstack.com/2013/04/13/setting-ubuntu-vm-in-virtualbox/)
### Required Programs
Assuming the minimal install, there are several programs that we will need to install before Zeppelin, Flink, and Spark.
- git
- openssh-server
- OpenJDK 7
- Maven 3.1+
For git, openssh-server, and OpenJDK 7 we will be using the apt package manager.
##### git
From the command prompt:
```
sudo apt-get install git
```
##### openssh-server
```
sudo apt-get install openssh-server
```
##### OpenJDK 7
```
sudo apt-get install openjdk-7-jdk openjdk-7-jre-lib
```
*A note for those using Ubuntu 16.04*: To install `openjdk-7` on Ubuntu 16.04, one must add a repository. [Source](http://askubuntu.com/questions/761127/ubuntu-16-04-and-openjdk-7)
``` bash
sudo add-apt-repository ppa:openjdk-r/ppa
sudo apt-get update
sudo apt-get install openjdk-7-jdk openjdk-7-jre-lib
```
##### Maven 3.1+
Zeppelin requires maven version 3.x. The version available in the repositories at the time of writing is 2.x, so maven must be installed manually.
Purge any existing versions of maven.
```
sudo apt-get purge maven maven2
```
Download the maven 3.3.9 binary.
```
wget "http://www.us.apache.org/dist/maven/maven-3/3.3.9/binaries/apache-maven-3.3.9-bin.tar.gz"
```
Unarchive the binary and move to the `/usr/local` directory.
```
tar -zxvf apache-maven-3.3.9-bin.tar.gz
sudo mv ./apache-maven-3.3.9 /usr/local
```
Create symbolic links in `/usr/bin`.
```
sudo ln -s /usr/local/apache-maven-3.3.9/bin/mvn /usr/bin/mvn
```
### Installing Zeppelin
This provides a quick overview of Zeppelin installation from source, however the reader is encouraged to review the [Zeppelin Installation Guide](../install/install.html)
From the command prompt:
Clone Zeppelin.
```
git clone https://github.com/apache/zeppelin.git
```
Enter the Zeppelin root directory.
```
cd zeppelin
```
Package Zeppelin.
```
mvn clean package -DskipTests -Pspark-1.6 -Dflink.version=1.1.2
```
`-DskipTests` skips build tests- you're not developing (yet), so you don't need to do tests, the clone version *should* build.
`-Pspark-1.6` tells maven to build a Zeppelin with Spark 1.6. This is important because Zeppelin has its own Spark interpreter and the versions must be the same.
`-Dflink.version=1.1.2` tells maven specifically to build Zeppelin with Flink version 1.1.2.
**Note:** You may wish to include additional build flags such as `-Ppyspark` or `-Psparkr`. See [the build section of github for more details](https://github.com/apache/zeppelin#build).
**Note:** You can build against any version of Spark that has a Zeppelin build profile available. The key is to make sure you check out the matching version of Spark to build. At the time of this writing, Spark 1.6 was the most recent Spark version available.
**Note:** On build failures. Having installed Zeppelin close to 30 times now, I will tell you that sometimes the build fails for seemingly no reason.
As long as you didn't edit any code, it is unlikely the build is failing because of something you did. What does tend to happen, is some dependency that maven is trying to download is unreachable. If your build fails on this step here are some tips:
- Don't get discouraged.
- Scroll up and read through the logs. There will be clues there.
- Retry (that is, run the `mvn clean package -DskipTests -Pspark-1.6` again)
- If there were clues that a dependency couldn't be downloaded wait a few hours or even days and retry again. Open source software when compiling is trying to download all of the dependencies it needs, if a server is off-line there is nothing you can do but wait for it to come back.
- Make sure you followed all of the steps carefully.
- Ask the community to help you. Go [here](http://zeppelin.apache.org/community.html) and join the user mailing list. People are there to help you. Make sure to copy and paste the build output (everything that happened in the console) and include that in your message.
Start the Zeppelin daemon.
```
bin/zeppelin-daemon.sh start
```
Use `ifconfig` to determine the host machine's IP address. If you are not familiar with how to do this, a fairly comprehensive post can be found [here](http://www.cyberciti.biz/faq/how-to-find-out-the-ip-address-assigned-to-eth0-and-display-ip-only/).
Open a web-browser on a machine connected to the same network as the host (or in the host operating system if using a virtual machine). Navigate to http://`yourip`:8080, where yourip is the IP address you found in `ifconfig`.
See the [Zeppelin tutorial](../tutorial/tutorial.md) for basic Zeppelin usage. It is also advised that you take a moment to check out the tutorial notebook that is included with each Zeppelin install, and to familiarize yourself with basic notebook functionality.
##### Flink Test
Create a new notebook named "Flink Test" and copy and paste the following code.
```scala
%flink // let Zeppelin know what interpreter to use.
val text = env.fromElements("In the time of chimpanzees, I was a monkey", // some lines of text to analyze
"Butane in my veins and I'm out to cut the junkie",
"With the plastic eyeballs, spray paint the vegetables",
"Dog food stalls with the beefcake pantyhose",
"Kill the headlights and put it in neutral",
"Stock car flamin' with a loser in the cruise control",
"Baby's in Reno with the Vitamin D",
"Got a couple of couches, sleep on the love seat",
"Someone came in sayin' I'm insane to complain",
"About a shotgun wedding and a stain on my shirt",
"Don't believe everything that you breathe",
"You get a parking violation and a maggot on your sleeve",
"So shave your face with some mace in the dark",
"Savin' all your food stamps and burnin' down the trailer park",
"Yo, cut it")
/* The meat and potatoes:
this tells Flink to iterate through the elements, in this case strings,
transform the string to lower case and split the string at white space into individual words
then finally aggregate the occurrence of each word.
This creates the count variable which is a list of tuples of the form (word, occurances)
counts.collect().foreach(println(_)) // execute the script and print each element in the counts list
*/
val counts = text.flatMap{ _.toLowerCase.split("\\W+") }.map { (_,1) }.groupBy(0).sum(1)
counts.collect().foreach(println(_)) // execute the script and print each element in the counts list
```
Run the code to make sure the built-in Zeppelin Flink interpreter is working properly.
##### Spark Test
Create a new notebook named "Spark Test" and copy and paste the following code.
```scala
%spark // let Zeppelin know what interpreter to use.
val text = sc.parallelize(List("In the time of chimpanzees, I was a monkey", // some lines of text to analyze
"Butane in my veins and I'm out to cut the junkie",
"With the plastic eyeballs, spray paint the vegetables",
"Dog food stalls with the beefcake pantyhose",
"Kill the headlights and put it in neutral",
"Stock car flamin' with a loser in the cruise control",
"Baby's in Reno with the Vitamin D",
"Got a couple of couches, sleep on the love seat",
"Someone came in sayin' I'm insane to complain",
"About a shotgun wedding and a stain on my shirt",
"Don't believe everything that you breathe",
"You get a parking violation and a maggot on your sleeve",
"So shave your face with some mace in the dark",
"Savin' all your food stamps and burnin' down the trailer park",
"Yo, cut it"))
/* The meat and potatoes:
this tells spark to iterate through the elements, in this case strings,
transform the string to lower case and split the string at white space into individual words
then finally aggregate the occurrence of each word.
This creates the count variable which is a list of tuples of the form (word, occurances)
*/
val counts = text.flatMap { _.toLowerCase.split("\\W+") }
.map { (_,1) }
.reduceByKey(_ + _)
counts.collect().foreach(println(_)) // execute the script and print each element in the counts list
```
Run the code to make sure the built-in Zeppelin Flink interpreter is working properly.
Finally, stop the Zeppelin daemon. From the command prompt run:
```
bin/zeppelin-daemon.sh stop
```
### Installing Clusters
##### Flink Cluster
###### Download Binaries
Building from source is recommended where possible, for simplicity in this tutorial we will download Flink and Spark Binaries.
To download the Flink Binary use `wget`
```bash
wget "http://mirror.cogentco.com/pub/apache/flink/flink-1.0.3/flink-1.0.3-bin-hadoop24-scala_2.10.tgz"
tar -xzvf flink-1.0.3-bin-hadoop24-scala_2.10.tgz
```
This will download Flink 1.0.3, compatible with Hadoop 2.4. You do not have to install Hadoop for this binary to work, but if you are using Hadoop, please change `24` to your appropriate version.
Start the Flink Cluster.
```bash
flink-1.0.3/bin/start-cluster.sh
```
###### Building From source
If you wish to build Flink from source, the following will be instructive. Note that if you have downloaded and used the binary version this should be skipped. The changing nature of build tools and versions across platforms makes this section somewhat precarious. For example, Java8 and Maven 3.0.3 are recommended for building Flink, which are not recommended for Zeppelin at the time of writing. If the user wishes to attempt to build from source, this section will provide some reference. If errors are encountered, please contact the Apache Flink community.
See the [Flink Installation guide](https://github.com/apache/flink/blob/master/README.md) for more detailed instructions.
Return to the directory where you have been downloading, this tutorial assumes that is `$HOME`. Clone Flink, check out release-1.0, and build.
```
cd $HOME
git clone https://github.com/apache/flink.git
cd flink
git checkout release-1.0
mvn clean install -DskipTests
```
Start the Flink Cluster in stand-alone mode
```
build-target/bin/start-cluster.sh
```
###### Ensure the cluster is up
In a browser, navigate to http://`yourip`:8082 to see the Flink Web-UI. Click on 'Task Managers' in the left navigation bar. Ensure there is at least one Task Manager present.
<center>![alt text](../assets/themes/zeppelin/img/screenshots/flink-webui.png "The Flink Web-UI")</center>
If no task managers are present, restart the Flink cluster with the following commands:
(if binaries)
```
flink-1.0.3/bin/stop-cluster.sh
flink-1.0.3/bin/start-cluster.sh
```
(if built from source)
```
build-target/bin/stop-cluster.sh
build-target/bin/start-cluster.sh
```
##### Spark 1.6 Cluster
###### Download Binaries
Building from source is recommended where possible, for simplicity in this tutorial we will download Flink and Spark Binaries.
Using binaries is also
To download the Spark Binary use `wget`
```bash
wget "http://mirrors.koehn.com/apache/spark/spark-1.6.1/spark-1.6.1-bin-hadoop2.4.tgz"
tar -xzvf spark-1.6.1-bin-hadoop2.4.tgz
mv spark-1.6.1-bin-hadoop4.4 spark
```
This will download Spark 1.6.1, compatible with Hadoop 2.4. You do not have to install Hadoop for this binary to work, but if you are using Hadoop, please change `2.4` to your appropriate version.
###### Building From source
Spark is an extraordinarily large project, which takes considerable time to download and build. It is also prone to build failures for similar reasons listed in the Flink section. If the user wishes to attempt to build from source, this section will provide some reference. If errors are encountered, please contact the Apache Spark community.
See the [Spark Installation](https://github.com/apache/spark/blob/master/README.md) guide for more detailed instructions.
Return to the directory where you have been downloading, this tutorial assumes that is $HOME. Clone Spark, check out branch-1.6, and build.
**Note:** Recall, we're only checking out 1.6 because it is the most recent Spark for which a Zeppelin profile exists at
the time of writing. You are free to check out other version, just make sure you build Zeppelin against the correct version of Spark.
```
cd $HOME
```
Clone, check out, and build Spark version 1.6.x.
```
git clone https://github.com/apache/spark.git
cd spark
git checkout branch-1.6
mvn clean package -DskipTests
```
###### Start the Spark cluster
Return to the `$HOME` directory.
```bash
cd $HOME
```
Start the Spark cluster in stand alone mode, specifying the webui-port as some port other than 8080 (the webui-port of Zeppelin).
```
spark/sbin/start-master.sh --webui-port 8082
```
**Note:** Why `--webui-port 8082`? There is a digression toward the end of this document that explains this.
Open a browser and navigate to http://`yourip`:8082 to ensure the Spark master is running.
<center>![alt text](../assets/themes/zeppelin/img/screenshots/spark-master-webui1.png "It should look like this...")</center>
Toward the top of the page there will be a *URL*: spark://`yourhost`:7077. Note this URL, the Spark Master URI, it will be needed in subsequent steps.
Start the slave using the URI from the Spark master WebUI:
```
spark/sbin/start-slave.sh spark://yourhostname:7077
```
Return to the root directory and start the Zeppelin daemon.
```
cd $HOME
zeppelin/bin/zeppelin-daemon.sh start
```
##### Configure Interpreters
Open a web browser and go to the Zeppelin web-ui at http://yourip:8080.
Now go back to the Zeppelin web-ui at http://`yourip`:8080 and this time click on *anonymous* at the top right, which will open a drop-down menu, select *Interpreters* to enter interpreter configuration.
In the Spark section, click the edit button in the top right corner to make the property values editable (looks like a pencil).
The only field that needs to be edited in the Spark interpreter is the master field. Change this value from `local[*]` to the URL you used to start the slave, mine was `spark://ubuntu:7077`.
Click *Save* to update the parameters, and click *OK* when it asks you about restarting the interpreter.
Now scroll down to the Flink section. Click the edit button and change the value of *host* from `local` to `localhost`. Click *Save* again.
Reopen the examples and execute them again (I.e. you need to click the play button at the top of the screen, or the button on the paragraph .
You should be able check the Flink and Spark webuis (at something like http://`yourip`:8081, http://`yourip`:8082, http://`yourip`:8083) and see that jobs have been run against the clusters.
**Digression** Sorry to be vague and use terms such as 'something like', but exactly what web-ui is at what port is going to depend on what order you started things.
What is really going on here is you are pointing your browser at specific ports, namely 8081, 8082, and 8083. Flink and Spark all want to put their web-ui on port 8080, but are
well behaved and will take the next port available. Since Zeppelin started first, it will get port 8080. When Flink starts (assuming you started Flink first), it will try to bind to
port 8080, see that it is already taken, and go to the next one available, hopefully 8081. Spark has a webui for the master and the slave, so when they start they will try to bind to 8080
already taken by Zeppelin), then 8081 (already taken by Flink's webui), then 8082. If everything goes smoothy and you followed the directions precisely, the webuis should be 8081 and 8082.
It *is* possible to specify the port you want the webui to bind to (at the command line by passing the `--webui-port <port>` flag when you start the Flink and Spark, where `<port>` is the port
you want to see that webui on. You can also set the default webui port of Spark and Flink (and Zeppelin) in the configuration files, but this is a tutorial for novices and slightly out of scope.
### Next Steps
Check out the [tutorial](./tutorial.md) for more cool things you can do with your new toy!
[Join the community](http://zeppelin.apache.org/community.html), ask questions and contribute! Every little bit helps.

View file

@ -1,6 +1,6 @@
---
layout: nil
title : RSS Feed
title :
---
<?xml version="1.0" encoding="UTF-8" ?>

View file

@ -57,5 +57,5 @@ You have to store the password information for users.
## Please note
As a first step of data source authentication feature, [ZEPPELIN-828](https://issues.apache.org/jira/browse/ZEPPELIN-828) was proposed and implemented in Pull Request [#860](https://github.com/apache/zeppelin/pull/860).
Currently, only customized 3rd party interpreters can use this feature. We are planning to apply this mechanism to [the community interpreters](../manual/interpreterinstallation.md#available-community-managed-interpreters) in the near future.
Currently, only customized 3rd party interpreters can use this feature. We are planning to apply this mechanism to [the community managed interpreters](../manual/interpreterinstallation.html#available-community-managed-interpreters) in the near future.
Please keep track [ZEPPELIN-1070](https://issues.apache.org/jira/browse/ZEPPELIN-1070).

View file

@ -1,6 +1,6 @@
---
# Remember to set production_url in your _config.yml file!
title : Sitemap
title :
---
{% for page in site.pages %}
{{site.production_url}}{{ page.url }}{% endfor %}

View file

@ -104,6 +104,12 @@
<version>1.0.8</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.0.1</version>
</dependency>
</dependencies>
<build>

View file

@ -19,15 +19,16 @@ import java.io.*;
import java.nio.charset.StandardCharsets;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.*;
import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDriver;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.ObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.zeppelin.interpreter.Interpreter;
import org.apache.zeppelin.interpreter.InterpreterContext;
@ -99,14 +100,15 @@ public class JDBCInterpreter extends Interpreter {
static final String EMPTY_COLUMN_VALUE = "";
private final String CONCURRENT_EXECUTION_KEY = "zeppelin.jdbc.concurrent.use";
private final String CONCURRENT_EXECUTION_COUNT = "zeppelin.jdbc.concurrent.max_connection";
private final String DBCP_STRING = "jdbc:apache:commons:dbcp:";
private final HashMap<String, Properties> propertiesMap;
private final Map<String, Statement> paragraphIdStatementMap;
private final Map<String, ArrayList<Connection>> propertyKeyUnusedConnectionListMap;
private final Map<String, Connection> paragraphIdConnectionMap;
private final Map<String, PoolingDriver> poolingDriverMap;
private final Map<String, SqlCompleter> propertyKeySqlCompleterMap;
@ -122,9 +124,8 @@ public class JDBCInterpreter extends Interpreter {
public JDBCInterpreter(Properties property) {
super(property);
propertiesMap = new HashMap<>();
propertyKeyUnusedConnectionListMap = new HashMap<>();
paragraphIdStatementMap = new HashMap<>();
paragraphIdConnectionMap = new HashMap<>();
poolingDriverMap = new HashMap<>();
propertyKeySqlCompleterMap = new HashMap<>();
}
@ -193,22 +194,41 @@ public class JDBCInterpreter extends Interpreter {
return completer;
}
private boolean isConnectionInPool(String driverName) {
if (poolingDriverMap.containsKey(driverName)) return true;
return false;
}
private void createConnectionPool(String url, String propertyKey, Properties properties) {
ConnectionFactory connectionFactory =
new DriverManagerConnectionFactory(url, properties);
PoolableConnectionFactory poolableConnectionFactory = new PoolableConnectionFactory(
connectionFactory, null);
ObjectPool connectionPool = new GenericObjectPool(poolableConnectionFactory);
poolableConnectionFactory.setPool(connectionPool);
PoolingDriver driver = new PoolingDriver();
driver.registerPool(propertyKey, connectionPool);
poolingDriverMap.put(propertyKey, driver);
}
private Connection getConnectionFromPool(String url, String propertyKey, Properties properties)
throws SQLException {
if (!isConnectionInPool(propertyKey)) {
createConnectionPool(url, propertyKey, properties);
}
return DriverManager.getConnection(DBCP_STRING + propertyKey);
}
public Connection getConnection(String propertyKey, String user)
throws ClassNotFoundException, SQLException, InterpreterException {
Connection connection = null;
if (propertyKey == null || propertiesMap.get(propertyKey) == null) {
return null;
}
if (propertyKeyUnusedConnectionListMap.containsKey(propertyKey)) {
ArrayList<Connection> connectionList = propertyKeyUnusedConnectionListMap.get(propertyKey);
if (0 != connectionList.size()) {
connection = propertyKeyUnusedConnectionListMap.get(propertyKey).remove(0);
if (null != connection && connection.isClosed()) {
connection.close();
connection = null;
}
}
}
if (null == connection) {
final Properties properties = (Properties) propertiesMap.get(propertyKey).clone();
logger.info(properties.getProperty(DRIVER_KEY));
@ -222,16 +242,16 @@ public class JDBCInterpreter extends Interpreter {
switch (authType) {
case KERBEROS:
if (user == null) {
connection = DriverManager.getConnection(url, properties);
connection = getConnectionFromPool(url, propertyKey, properties);
} else {
if ("hive".equalsIgnoreCase(propertyKey)) {
connection = DriverManager.getConnection(url + ";hive.server2.proxy.user=" + user,
properties);
connection = getConnectionFromPool(url + ";hive.server2.proxy.user=" + user,
propertyKey, properties);
} else {
UserGroupInformation ugi = null;
try {
ugi = UserGroupInformation.createProxyUser(user,
UserGroupInformation.getCurrentUser());
UserGroupInformation.getCurrentUser());
} catch (Exception e) {
logger.error("Error in createProxyUser", e);
StringBuilder stringBuilder = new StringBuilder();
@ -239,11 +259,13 @@ public class JDBCInterpreter extends Interpreter {
stringBuilder.append(e.getCause());
throw new InterpreterException(stringBuilder.toString());
}
final String poolKey = propertyKey;
try {
connection = ugi.doAs(new PrivilegedExceptionAction<Connection>() {
@Override
public Connection run() throws Exception {
return DriverManager.getConnection(url, properties);
return getConnectionFromPool(url, poolKey, properties);
}
});
} catch (Exception e) {
@ -258,7 +280,7 @@ public class JDBCInterpreter extends Interpreter {
break;
default:
connection = DriverManager.getConnection(url, properties);
connection = getConnectionFromPool(url, propertyKey, properties);
}
}
}
@ -266,75 +288,41 @@ public class JDBCInterpreter extends Interpreter {
return connection;
}
public Statement getStatement(String propertyKey, String paragraphId,
InterpreterContext interpreterContext)
throws SQLException, ClassNotFoundException, InterpreterException {
Connection connection;
if (paragraphIdConnectionMap.containsKey(paragraphId +
interpreterContext.getAuthenticationInfo().getUser())) {
connection = paragraphIdConnectionMap.get(paragraphId +
interpreterContext.getAuthenticationInfo().getUser());
} else {
connection = getConnection(propertyKey, interpreterContext.getAuthenticationInfo().getUser());
private void initStatementMap() {
for (Statement statement : paragraphIdStatementMap.values()) {
try {
statement.close();
} catch (Exception e) {
logger.error("Error while closing paragraphIdStatementMap statement...", e);
}
}
if (connection == null) {
return null;
}
Statement statement = connection.createStatement();
if (isStatementClosed(statement)) {
connection = getConnection(propertyKey, interpreterContext.getAuthenticationInfo().getUser());
statement = connection.createStatement();
}
paragraphIdConnectionMap.put(paragraphId + interpreterContext.getAuthenticationInfo().getUser(),
connection);
paragraphIdStatementMap.put(paragraphId + interpreterContext.getAuthenticationInfo().getUser(),
statement);
return statement;
paragraphIdStatementMap.clear();
}
private boolean isStatementClosed(Statement statement) {
try {
return statement.isClosed();
} catch (Throwable t) {
logger.debug("{} doesn't support isClosed method", statement);
return false;
private void initConnectionPoolMap() throws SQLException {
Iterator<String> it = poolingDriverMap.keySet().iterator();
while (it.hasNext()) {
String driverName = it.next();
poolingDriverMap.get(driverName).closePool(driverName);
it.remove();
}
poolingDriverMap.clear();
}
private void saveStatement(String key, Statement statement) throws SQLException {
paragraphIdStatementMap.put(key, statement);
statement.setMaxRows(getMaxResult());
}
private void removeStatement(String key) {
paragraphIdStatementMap.remove(key);
}
@Override
public void close() {
try {
for (List<Connection> connectionList : propertyKeyUnusedConnectionListMap.values()) {
for (Connection c : connectionList) {
try {
c.close();
} catch (Exception e) {
logger.error("Error while closing propertyKeyUnusedConnectionListMap connection...", e);
}
}
}
for (Statement statement : paragraphIdStatementMap.values()) {
try {
statement.close();
} catch (Exception e) {
logger.error("Error while closing paragraphIdStatementMap statement...", e);
}
}
paragraphIdStatementMap.clear();
for (Connection connection : paragraphIdConnectionMap.values()) {
try {
connection.close();
} catch (Exception e) {
logger.error("Error while closing paragraphIdConnectionMap connection...", e);
}
}
paragraphIdConnectionMap.clear();
initStatementMap();
initConnectionPoolMap();
} catch (Exception e) {
logger.error("Error while closing...", e);
}
@ -342,17 +330,21 @@ public class JDBCInterpreter extends Interpreter {
private InterpreterResult executeSql(String propertyKey, String sql,
InterpreterContext interpreterContext) {
String paragraphId = interpreterContext.getParagraphId();
Connection connection;
Statement statement;
ResultSet resultSet = null;
try {
connection = getConnection(propertyKey, interpreterContext.getAuthenticationInfo().getUser());
if (connection == null) {
return new InterpreterResult(Code.ERROR, "Prefix not found.");
}
Statement statement = getStatement(propertyKey, paragraphId, interpreterContext);
statement = connection.createStatement();
if (statement == null) {
return new InterpreterResult(Code.ERROR, "Prefix not found.");
}
statement.setMaxRows(getMaxResult());
StringBuilder msg = null;
boolean isTableType = false;
@ -364,8 +356,9 @@ public class JDBCInterpreter extends Interpreter {
isTableType = true;
}
ResultSet resultSet = null;
try {
saveStatement(paragraphId +
interpreterContext.getAuthenticationInfo().getUser(), statement);
boolean isResultSetAvailable = statement.execute(sql);
@ -408,16 +401,24 @@ public class JDBCInterpreter extends Interpreter {
msg.append(updateCount).append(NEWLINE);
}
} finally {
try {
if (resultSet != null) {
if (resultSet != null) {
try {
resultSet.close();
}
statement.close();
} finally {
statement = null;
} catch (SQLException e) { /*ignored*/ }
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) { /*ignored*/ }
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) { /*ignored*/ }
}
removeStatement(paragraphId +
interpreterContext.getAuthenticationInfo().getUser());
}
return new InterpreterResult(Code.SUCCESS, msg.toString());
} catch (Exception e) {
@ -452,7 +453,6 @@ public class JDBCInterpreter extends Interpreter {
cmd = cmd.trim();
logger.info("PropertyKey: {}, SQL command: '{}'", propertyKey, cmd);
return executeSql(propertyKey, cmd, contextInterpreter);
}

View file

@ -72,6 +72,16 @@
<groupId>org.apache.lens</groupId>
<artifactId>lens-client</artifactId>
<version>${lens.version}</version>
<exclusions>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>

View file

@ -34,8 +34,8 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** MarkdownInterpreter interpreter for Zeppelin. */
public class MarkdownInterpreter extends Interpreter {
private static final Logger LOGGER = LoggerFactory.getLogger(MarkdownInterpreter.class);
public class Markdown extends Interpreter {
private static final Logger LOGGER = LoggerFactory.getLogger(Markdown.class);
private MarkdownParser parser;
@ -60,7 +60,7 @@ public class MarkdownInterpreter extends Interpreter {
public static final String PARSER_TYPE_PEGDOWN = "pegdown";
public static final String PARSER_TYPE_MARKDOWN4J = "markdown4j";
public MarkdownInterpreter(Properties property) {
public Markdown(Properties property) {
super(property);
}
@ -114,7 +114,7 @@ public class MarkdownInterpreter extends Interpreter {
@Override
public Scheduler getScheduler() {
return SchedulerFactory.singleton()
.createOrGetParallelScheduler(MarkdownInterpreter.class.getName() + this.hashCode(), 5);
.createOrGetParallelScheduler(Markdown.class.getName() + this.hashCode(), 5);
}
@Override

View file

@ -2,7 +2,7 @@
{
"group": "md",
"name": "md",
"className": "org.apache.zeppelin.markdown.MarkdownInterpreter",
"className": "org.apache.zeppelin.markdown.Markdown",
"properties": {
"markdown.parser.type": {
"envName": "MARKDOWN_PARSER_TYPE",

View file

@ -28,13 +28,13 @@ import static org.junit.Assert.assertEquals;
public class Markdown4jParserTest {
MarkdownInterpreter md;
Markdown md;
@Before
public void setUp() throws Exception {
Properties props = new Properties();
props.put(MarkdownInterpreter.MARKDOWN_PARSER_TYPE, MarkdownInterpreter.PARSER_TYPE_MARKDOWN4J);
md = new MarkdownInterpreter(props);
props.put(Markdown.MARKDOWN_PARSER_TYPE, Markdown.PARSER_TYPE_MARKDOWN4J);
md = new Markdown(props);
md.open();
}

View file

@ -29,13 +29,13 @@ import org.junit.Test;
public class PegdownParserTest {
MarkdownInterpreter md;
Markdown md;
@Before
public void setUp() throws Exception {
Properties props = new Properties();
props.put(MarkdownInterpreter.MARKDOWN_PARSER_TYPE, MarkdownInterpreter.PARSER_TYPE_PEGDOWN);
md = new MarkdownInterpreter(props);
props.put(Markdown.MARKDOWN_PARSER_TYPE, Markdown.PARSER_TYPE_PEGDOWN);
md = new Markdown(props);
md.open();
}

View file

@ -579,6 +579,13 @@
</modules>
</profile>
<profile>
<id>beam</id>
<modules>
<module>beam</module>
</modules>
</profile>
<profile>
<id>examples</id>
<modules>
@ -746,6 +753,7 @@
<exclude>.spark-dist/**</exclude>
<exclude>**/interpreter-setting.json</exclude>
<exclude>**/constants.json</exclude>
<exclude>scripts/**</exclude>
<!-- bundled from bootstrap -->
<exclude>docs/assets/themes/zeppelin/bootstrap/**</exclude>

View file

@ -0,0 +1,6 @@
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://0.0.0.0:8020</value>
</property>
</configuration>

View file

@ -0,0 +1,64 @@
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>/data/hdfs</value>
<final>true</final>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
<property>
<name>dfs.client.use.datanode.hostname</name>
<value>true</value>
<description>Whether clients should use datanode hostnames when
connecting to datanodes.
</description>
</property>
<property>
<name>dfs.datanode.use.datanode.hostname</name>
<value>true</value>
<description>Whether datanodes should use datanode hostnames when
connecting to other datanodes for data transfer.
</description>
</property>
<property>
<name>dfs.datanode.address</name>
<value>0.0.0.0:50010</value>
<description>
The address where the datanode server will listen to.
If the port is 0 then the server will start on a free port.
</description>
</property>
<property>
<name>dfs.datanode.http.address</name>
<value>0.0.0.0:50075</value>
<description>
The datanode http server address and port.
If the port is 0 then the server will start on a free port.
</description>
</property>
<property>
<name>dfs.datanode.ipc.address</name>
<value>0.0.0.0:50020</value>
<description>
The datanode ipc server address and port.
If the port is 0 then the server will start on a free port.
</description>
</property>
</configuration>

View file

@ -0,0 +1,6 @@
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

View file

@ -0,0 +1,26 @@
<configuration>
<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>0.0.0.0:8030</value>
</property>
<property>
<name>yarn.resourcemanager.address</name>
<value>0.0.0.0:8032</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>0.0.0.0:8088</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>0.0.0.0:8031</value>
</property>
<property>
<name>yarn.resourcemanager.admin.address</name>
<value>0.0.0.0:8033</value>
</property>
<property>
<name>yarn.application.classpath</name>
<value>/usr/local/hadoop/etc/hadoop, /usr/local/hadoop/share/hadoop/common/*, /usr/local/hadoop/share/hadoop/common/lib/*, /usr/local/hadoop/share/hadoop/hdfs/*, /usr/local/hadoop/share/hadoop/hdfs/lib/*, /usr/local/hadoop/share/hadoop/mapreduce/*, /usr/local/hadoop/share/hadoop/mapreduce/lib/*, /usr/local/hadoop/share/hadoop/yarn/*, /usr/local/hadoop/share/hadoop/yarn/lib/*, /usr/local/hadoop/share/spark/*</value>
</property>
</configuration>

View file

@ -384,6 +384,7 @@ public class SparkInterpreter extends Interpreter {
}
String classServerUri = null;
String replClassOutputDirectory = null;
try { // in case of spark 1.1x, spark 1.2x
Method classServer = intp.getClass().getMethod("classServer");
@ -407,6 +408,16 @@ public class SparkInterpreter extends Interpreter {
}
}
if (classServerUri == null) {
try { // for RcpEnv
Method getClassOutputDirectory = intp.getClass().getMethod("getClassOutputDirectory");
File classOutputDirectory = (File) getClassOutputDirectory.invoke(intp);
replClassOutputDirectory = classOutputDirectory.getAbsolutePath();
} catch (NoSuchMethodException | SecurityException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException e) {
// continue
}
}
if (Utils.isScala2_11()) {
classServer = createHttpServer(outputDir);
@ -421,6 +432,10 @@ public class SparkInterpreter extends Interpreter {
conf.set("spark.repl.class.uri", classServerUri);
}
if (replClassOutputDirectory != null) {
conf.set("spark.repl.class.outputDir", replClassOutputDirectory);
}
if (jars.length > 0) {
conf.setJars(jars);
}
@ -584,6 +599,24 @@ public class SparkInterpreter extends Interpreter {
argList.add(arg);
}
DepInterpreter depInterpreter = getDepInterpreter();
String depInterpreterClasspath = "";
if (depInterpreter != null) {
SparkDependencyContext depc = depInterpreter.getDependencyContext();
if (depc != null) {
List<File> files = depc.getFiles();
if (files != null) {
for (File f : files) {
if (depInterpreterClasspath.length() > 0) {
depInterpreterClasspath += File.pathSeparator;
}
depInterpreterClasspath += f.getAbsolutePath();
}
}
}
}
if (Utils.isScala2_10()) {
scala.collection.immutable.List<String> list =
JavaConversions.asScalaBuffer(argList).toList();
@ -611,10 +644,22 @@ public class SparkInterpreter extends Interpreter {
argList.add("-Yrepl-class-based");
argList.add("-Yrepl-outdir");
argList.add(outputDir.getAbsolutePath());
String classpath = "";
if (conf.contains("spark.jars")) {
String jars = StringUtils.join(conf.get("spark.jars").split(","), File.separator);
classpath = StringUtils.join(conf.get("spark.jars").split(","), File.separator);
}
if (!depInterpreterClasspath.isEmpty()) {
if (!classpath.isEmpty()) {
classpath += File.separator;
}
classpath += depInterpreterClasspath;
}
if (!classpath.isEmpty()) {
argList.add("-classpath");
argList.add(jars);
argList.add(classpath);
}
scala.collection.immutable.List<String> list =
@ -626,6 +671,7 @@ public class SparkInterpreter extends Interpreter {
// set classpath for scala compiler
PathSetting pathSettings = settings.classpath();
String classpath = "";
List<File> paths = currentClassPath();
for (File f : paths) {
if (classpath.length() > 0) {
@ -644,21 +690,10 @@ public class SparkInterpreter extends Interpreter {
}
// add dependency from DepInterpreter
DepInterpreter depInterpreter = getDepInterpreter();
if (depInterpreter != null) {
SparkDependencyContext depc = depInterpreter.getDependencyContext();
if (depc != null) {
List<File> files = depc.getFiles();
if (files != null) {
for (File f : files) {
if (classpath.length() > 0) {
classpath += File.pathSeparator;
}
classpath += f.getAbsolutePath();
}
}
}
if (classpath.length() > 0) {
classpath += File.pathSeparator;
}
classpath += depInterpreterClasspath;
// add dependency from local repo
String localRepo = getProperty("zeppelin.interpreter.localRepo");

View file

@ -178,20 +178,29 @@ public class SparkInterpreterTest {
@Test
public void testCreateDataFrame() {
repl.interpret("case class Person(name:String, age:Int)\n", context);
repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
repl.interpret("people.toDF.count", context);
assertEquals(new Long(4), context.getResourcePool().get(
context.getNoteId(),
context.getParagraphId(),
WellKnownResourceName.ZeppelinReplResult.toString()).get());
if (getSparkVersionNumber() >= 13) {
repl.interpret("case class Person(name:String, age:Int)\n", context);
repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
repl.interpret("people.toDF.count", context);
assertEquals(new Long(4), context.getResourcePool().get(
context.getNoteId(),
context.getParagraphId(),
WellKnownResourceName.ZeppelinReplResult.toString()).get());
}
}
@Test
public void testZShow() {
String code = "";
repl.interpret("case class Person(name:String, age:Int)\n", context);
repl.interpret("val people = sc.parallelize(Seq(Person(\"moon\", 33), Person(\"jobs\", 51), Person(\"gates\", 51), Person(\"park\", 34)))\n", context);
assertEquals(Code.SUCCESS, repl.interpret("z.show(people.toDF)", context).code());
if (getSparkVersionNumber() < 13) {
repl.interpret("people.registerTempTable(\"people\")", context);
code = "z.show(sqlc.sql(\"select * from people\"))";
} else {
code = "z.show(people.toDF)";
}
assertEquals(Code.SUCCESS, repl.interpret(code, context).code());
}
@Test
@ -203,14 +212,15 @@ public class SparkInterpreterTest {
if (getSparkVersionNumber() <= 11) { // spark 1.2 or later does not allow create multiple SparkContext in the same jvm by default.
// create new interpreter
Properties p = new Properties();
SparkInterpreter repl2 = new SparkInterpreter(p);
SparkInterpreter repl2 = new SparkInterpreter(getSparkTestProperties());
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
repl.interpret("case class Man(name:String, age:Int)", context);
repl.interpret("val man = sc.parallelize(Seq(Man(\"moon\", 33), Man(\"jobs\", 51), Man(\"gates\", 51), Man(\"park\", 34)))", context);
assertEquals(Code.SUCCESS, repl.interpret("man.take(3)", context).code());
repl2.getSparkContext().stop();
repl2.interpret("case class Man(name:String, age:Int)", context);
repl2.interpret("val man = sc.parallelize(Seq(Man(\"moon\", 33), Man(\"jobs\", 51), Man(\"gates\", 51), Man(\"park\", 34)))", context);
assertEquals(Code.SUCCESS, repl2.interpret("man.take(3)", context).code());
repl2.close();
}
}
@ -253,33 +263,37 @@ public class SparkInterpreterTest {
@Test
public void testEnableImplicitImport() {
// Set option of importing implicits to "true", and initialize new Spark repl
Properties p = getSparkTestProperties();
p.setProperty("zeppelin.spark.importImplicit", "true");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
if (getSparkVersionNumber() >= 13) {
// Set option of importing implicits to "true", and initialize new Spark repl
Properties p = getSparkTestProperties();
p.setProperty("zeppelin.spark.importImplicit", "true");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
String ddl = "val df = Seq((1, true), (2, false)).toDF(\"num\", \"bool\")";
assertEquals(Code.SUCCESS, repl2.interpret(ddl, context).code());
repl2.close();
repl2.open();
String ddl = "val df = Seq((1, true), (2, false)).toDF(\"num\", \"bool\")";
assertEquals(Code.SUCCESS, repl2.interpret(ddl, context).code());
repl2.close();
}
}
@Test
public void testDisableImplicitImport() {
// Set option of importing implicits to "false", and initialize new Spark repl
// this test should return error status when creating DataFrame from sequence
Properties p = getSparkTestProperties();
p.setProperty("zeppelin.spark.importImplicit", "false");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
if (getSparkVersionNumber() >= 13) {
// Set option of importing implicits to "false", and initialize new Spark repl
// this test should return error status when creating DataFrame from sequence
Properties p = getSparkTestProperties();
p.setProperty("zeppelin.spark.importImplicit", "false");
SparkInterpreter repl2 = new SparkInterpreter(p);
repl2.setInterpreterGroup(intpGroup);
intpGroup.get("note").add(repl2);
repl2.open();
String ddl = "val df = Seq((1, true), (2, false)).toDF(\"num\", \"bool\")";
assertEquals(Code.ERROR, repl2.interpret(ddl, context).code());
repl2.close();
repl2.open();
String ddl = "val df = Seq((1, true), (2, false)).toDF(\"num\", \"bool\")";
assertEquals(Code.ERROR, repl2.interpret(ddl, context).code());
repl2.close();
}
}
@Test

View file

@ -42,10 +42,12 @@ The following components are provided under Apache License.
(Apache 2.0) Apache Kylin (http://kylin.apache.org/)
(Apache 2.0) Apache Lens (http://lens.apache.org/)
(Apache 2.0) Apache Flink (http://flink.apache.org/)
(Apache 2.0) Apache Beam (http://beam.apache.org/)
(Apache 2.0) Apache Thrift (http://thrift.apache.org/)
(Apache 2.0) Apache Lucene (https://lucene.apache.org/)
(Apache 2.0) Apache Zookeeper (org.apache.zookeeper:zookeeper:jar:3.4.5 - http://zookeeper.apache.org/)
(Apache 2.0) Chill (com.twitter:chill-java:jar:0.8.0 - https://github.com/twitter/chill/)
(Apache 2.0) QDox (com.thoughtworks.qdox:qdox:jar:2.0-M3 - https://github.com/paul-hammant/qdox/)
(Apache 2.0) Codehaus Plexus (org.codehaus.plexus:plexus:jar:1.5.6 - https://codehaus-plexus.github.io/)
(Apache 2.0) findbugs jsr305 (com.google.code.findbugs:jsr305:jar:1.3.9 - http://findbugs.sourceforge.net/)
(Apache 2.0) Google Guava (com.google.guava:guava:15.0 - https://code.google.com/p/guava-libraries/)
@ -118,7 +120,43 @@ The following components are provided under Apache License.
(Apache 2.0) pegdown (org.pegdown:pegdown:1.6.0 - https://github.com/sirthias/pegdown)
(Apache 2.0) parboiled-java (org.parboiled:parboiled-java:1.1.7 - https://github.com/sirthias/parboiled)
(Apache 2.0) parboiled-core (org.parboiled:parboiled-core:1.1.7 - https://github.com/sirthias/parboiled)
(Apache 2.0) ZkClient (com.101tec:zkclient:0.7 - https://github.com/sgroschupf/zkclient)
(Apache 2.0) jackson-module-scala (com.fasterxml.jackson.module:jackson-module-scala_2.10:2.4.4 - http://wiki.fasterxml.com/JacksonModuleScala)
(Apache 2.0) BigQuery API v2-rev295-1.22.0 (com.google.apis:google-api-services-bigquery:v2-rev295-1.22.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-bigquery)
(Apache 2.0) Google Cloud Debugger API v2-rev8-1.22.0 (com.google.apis:google-api-services-clouddebugger:v2-rev8-1.22.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-clouddebugger)
(Apache 2.0) Google Dataflow API v1b3-rev30-1.22.0 (com.google.apis:google-api-services-dataflow:v1b3-rev30-1.22.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-dataflow)
(Apache 2.0) Google Cloud Pub/Sub API v1-rev10-1.22.0 (com.google.apis:google-api-services-pubsub:v1-rev10-1.22.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-pubsub)
(Apache 2.0) Cloud Storage JSON API v1-rev71-1.22.0 (com.google.apis:google-api-services-storage:v1-rev71-1.22.0 - http://nexus.sonatype.org/oss-repository-hosting.html/google-api-services-storage)
(Apache 2.0) gcsio.jar (com.google.cloud.bigdataoss:gcsio:1.4.5 - https://github.com/GoogleCloudPlatform/BigData-interop/gcsio/)
(Apache 2.0) util (com.google.cloud.bigdataoss:util:1.4.5 - https://github.com/GoogleCloudPlatform/BigData-interop/util/)
(Apache 2.0) Google Guice - Core Library (com.google.inject:guice:3.0 - http://code.google.com/p/google-guice/guice/)
(Apache 2.0) OkHttp (com.squareup.okhttp:okhttp:2.5.0 - https://github.com/square/okhttp/okhttp)
(Apache 2.0) Okio (com.squareup.okio:okio:1.6.0 - https://github.com/square/okio/okio)
(Apache 2.0) config (com.typesafe:config:1.2.1 - https://github.com/typesafehub/config)
(Apache 2.0) akka-actor (com.typesafe.akka:akka-actor_2.10:2.3.7 - http://akka.io/)
(Apache 2.0) akka-remote (com.typesafe.akka:akka-remote_2.10:2.3.7 - http://akka.io/)
(Apache 2.0) akka-slf4j (com.typesafe.akka:akka-slf4j_2.10:2.3.7 - http://akka.io/)
(Apache 2.0) Metrics Core Library (com.yammer.metrics:metrics-core:2.2.0 - http://metrics.codahale.com/metrics-core/)
(Apache 2.0) Commons BeanUtils Bean Collections (commons-beanutils:commons-beanutils-bean-collections:1.8.3 - http://commons.apache.org/beanutils/)
(Apache 2.0) Metrics Core (io.dropwizard.metrics:metrics-core:3.1.0 - http://metrics.codahale.com/metrics-core/)
(Apache 2.0) Graphite Integration for Metrics (io.dropwizard.metrics:metrics-graphite:3.1.0 - http://metrics.codahale.com/metrics-graphite/)
(Apache 2.0) Jackson Integration for Metrics (io.dropwizard.metrics:metrics-json:3.1.0 - http://metrics.codahale.com/metrics-json/)
(Apache 2.0) JVM Integration for Metrics (io.dropwizard.metrics:metrics-jvm:3.1.0 - http://metrics.codahale.com/metrics-jvm/)
(Apache 2.0) Apache Log4j (log4j:log4j:1.2.17 - http://logging.apache.org/log4j/1.2/)
(Apache 2.0) Apache Avro IPC (org.apache.avro:avro-ipc:1.8.1 - http://avro.apache.org)
(Apache 2.0) Apache Avro Mapred API (org.apache.avro:avro-mapred:1.8.1 - http://avro.apache.org/avro-mapred)
(Apache 2.0) Apache Ivy (org.apache.ivy:ivy:2.4.0 - http://ant.apache.org/ivy/)
(Apache 2.0) Apache Kafka (org.apache.kafka:kafka-clients:0.8.2.2 - http://kafka.apache.org)
(Apache 2.0) Apache Kafka (org.apache.kafka:kafka_2.10:0.8.2.2 - http://kafka.apache.org)
(Apache 2.0) mesos (org.apache.mesos:mesos:0.21.1 - http://mesos.apache.org)
(Apache 2.0) Apache Sling JSON Library (org.apache.sling:org.apache.sling.commons.json:2.0.6 - http://sling.apache.org/org.apache.sling.commons.json)
(Apache 2.0) Apache Velocity (org.apache.velocity:velocity:1.7 - http://velocity.apache.org/engine/devel/)
(Apache 2.0) jasper-compiler (tomcat:jasper-compiler:5.5.23 - http://tomcat.apache.org/jasper-compiler)
(Apache 2.0) jasper-runtime (tomcat:jasper-runtime:5.5.23 - http://tomcat.apache.org/jasper-runtime)
(Apache 2.0) Tachyon Project Core (org.tachyonproject:tachyon:0.6.4 - http://tachyonproject.org/tachyon/)
(Apache 2.0) Tachyon Project Client (org.tachyonproject:tachyon-client:0.6.4 - http://tachyonproject.org/tachyon-client/)
(Apache 2.0) javax.inject (javax.inject:javax.inject:1 - http://code.google.com/p/atinject/)
========================================================================
MIT licenses
========================================================================
@ -155,7 +193,7 @@ The text of each license is also included at licenses/LICENSE-[project]-[version
(The MIT License) AnchorJS (https://github.com/bryanbraun/anchorjs) - https://github.com/bryanbraun/anchorjs/blob/master/README.md#license
(The MIT License) moment-duration-format v1.3.0 (https://github.com/jsmreese/moment-duration-format) - https://github.com/jsmreese/moment-duration-format/blob/master/LICENSE
(The MIT License) github-markdown-css 2.4.0 (https://github.com/sindresorhus/github-markdown-css) - https://github.com/sindresorhus/github-markdown-css/blob/gh-pages/license
(The MIT License) scopt (com.github.scopt:scopt_2.10:3.2.0 - https://github.com/scopt/scopt)
The following components are provided under the MIT License.
(The MIT License) Objenesis (org.objenesis:objenesis:2.1 - https://github.com/easymock/objenesis) - Copyright (c) 2006-2015 the original author and authors
@ -180,9 +218,22 @@ The text of each license is also included at licenses/LICENSE-[project]-[version
(BSD 3 Clause) highlightjs v9.4.0 (https://highlightjs.org/) - https://github.com/isagalaev/highlight.js/blob/9.4.0/LICENSE
(BSD 3 Clause) hamcrest v1.3 (http://hamcrest.org/JavaHamcrest/) - http://opensource.org/licenses/BSD-3-Clause
(BSD Style) JLine v2.12.1 (https://github.com/jline/jline2) - https://github.com/jline/jline2/blob/master/LICENSE.txt
(BSD New license) Google Auth Library for Java - Credentials (com.google.auth:google-auth-library-credentials:0.4.0 - https://github.com/google/google-auth-library-java/google-auth-library-credentials)
(BSD New license) Google Auth Library for Java - OAuth2 HTTP (com.google.auth:google-auth-library-oauth2-http:0.4.0 - https://github.com/google/google-auth-library-java/google-auth-library-oauth2-http)
(New BSD license) Protocol Buffer Java API (com.google.protobuf:protobuf-java-util:3.0.0-beta-2 - https://developers.google.com/protocol-buffers/)
(New BSD license) Protocol Buffer JavaNano API (com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5 - https://developers.google.com/protocol-buffers/)
(BSD) JSch (com.jcraft:jsch:0.1.42 - http://www.jcraft.com/jsch/)
(BSD 3-Clause) io.grpc:grpc-all (io.grpc:grpc-all:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-auth (io.grpc:grpc-auth:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-core (io.grpc:grpc-core:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-netty (io.grpc:grpc-netty:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-okhttp (io.grpc:grpc-okhttp:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-protobuf (io.grpc:grpc-protobuf:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-protobuf-lite (io.grpc:grpc-protobuf-lite:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-protobuf-nano (io.grpc:grpc-protobuf-nano:0.14.1 - https://github.com/grpc/grpc-java)
(BSD 3-Clause) io.grpc:grpc-stub (io.grpc:grpc-stub:0.14.1 - https://github.com/grpc/grpc-java)
The following components are provided under the BSD-style License.
(New BSD License) JGit (org.eclipse.jgit:org.eclipse.jgit:jar:4.1.1.201511131810-r - https://eclipse.org/jgit/)
@ -202,6 +253,7 @@ The following components are provided under the BSD-style License.
(New BSD License) Markdown4j (org.commonjava.googlecode.markdown4j:markdown4j:jar:2.2-cj-1.0 - https://code.google.com/p/markdown4j/)
(New BSD License) Py4J (net.sf.py4j:py4j:0.9 - http://py4j.sourceforge.net/)
(New BSD License) Py4J (net.sf.py4j:py4j:0.10.1 - http://py4j.sourceforge.net/) - https://github.com/bartdag/py4j/blob/0.10.1/LICENSE.txt
(New BSD License) Markdown4j (org.commonjava.googlecode.markdown4j:markdown4j:jar:2.2-cj-1.0 - https://code.google.com/p/markdown4j/)
(BSD 3 Clause) Paranamer (com.thoughtworks.paranamer:paranamer:jar:2.6) - https://github.com/paul-hammant/paranamer/blob/paranamer-parent-2.6/LICENSE.txt
(BSD 3 Clause) netlib core (com.github.fommil.netlib:core:1.1.2 - https://github.com/fommil/netlib-java/core)
(BSD 3 Clause) JPMML-Model (org.jpmml:pmml-model:1.2.7 - https://github.com/jpmml/jpmml-model)
@ -225,8 +277,15 @@ The following components are provided under the CDDL License.
(CDDL 1.1) Jersey (com.sun.jersey:jersey:jar:1.9 - https://jersey.java.net/)
(CDDL 1.1) jersey-core (org.glassfish.jersey.core:jersey-core:2.22.2 - https://jersey.java.net/)
(CDDL 1.1) hk2 (org.glassfish.hk2 - https://hk2.java.net/2.5.0-b03/)
(CDDL 1.1) jersey-core (com.sun.jersey:jersey-core:1.9 - https://jersey.java.net/jersey-core/)
(CDDL 1.1) jersey-json (com.sun.jersey:jersey-json:1.9 - https://jersey.java.net/jersey-json/)
(CDDL 1.1) jersey-server (com.sun.jersey:jersey-server:1.9 - https://jersey.java.net/jersey-server/)
(CDDL 1.1) jersey-guice (com.sun.jersey.contribs:jersey-guice:1.9 - https://jersey.java.net/jersey-contribs/jersey-guice/)
(CDDL 1.1) JAXB RI (com.sun.xml.bind:jaxb-impl:2.2.3-1 - http://jaxb.java.net/)
(CDDL 1.0) Java Servlet API (javax.servlet:javax.servlet-api:3.1.0 - http://servlet-spec.java.net)
(CDDL 1.1) (GPL2 w/ CPE) JAXB API bundle for GlassFish V3 (javax.xml.bind:jaxb-api:2.2.2 - https://jaxb.dev.java.net/)
(CDDL 1.0) (GNU General Public Library) Streaming API for XML (javax.xml.stream:stax-api:1.0-2 - no url defined)
========================================================================
EPL license
@ -271,3 +330,5 @@ Creative Commons CC0 (http://creativecommons.org/publicdomain/zero/1.0/)
(CC0 1.0 Universal) JSR166e (com.twitter:jsr166e:1.1.0 - http://github.com/twitter/jsr166e)
(Public Domain, per Creative Commons CC0) HdrHistogram (org.hdrhistogram:HdrHistogram:2.1.6 - http://hdrhistogram.github.io/HdrHistogram/)
(Public Domain) XZ for Java (org.tukaani:xz:1.0 - http://tukaani.org/xz/java.html)
(Public Domain) AOP alliance (aopalliance:aopalliance:1.0 - http://aopalliance.sourceforge.net)

View file

@ -72,7 +72,7 @@ public abstract class AbstractDependencyResolver {
}
}
public void addRepo(String id, String url, boolean snapshot, Authentication auth) {
public void addRepo(String id, String url, boolean snapshot, Authentication auth, Proxy proxy) {
synchronized (repos) {
delRepo(id);
RemoteRepository rr = new RemoteRepository(id, "default", url);
@ -81,6 +81,7 @@ public abstract class AbstractDependencyResolver {
RepositoryPolicy.UPDATE_POLICY_DAILY,
RepositoryPolicy.CHECKSUM_POLICY_WARN));
rr.setAuthentication(auth);
rr.setProxy(proxy);
repos.add(rr);
}
}

View file

@ -33,6 +33,7 @@ import org.slf4j.LoggerFactory;
import org.sonatype.aether.RepositoryException;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.collection.CollectRequest;
import org.sonatype.aether.collection.DependencyCollectionException;
import org.sonatype.aether.graph.Dependency;
import org.sonatype.aether.graph.DependencyFilter;
import org.sonatype.aether.repository.RemoteRepository;
@ -42,6 +43,7 @@ import org.sonatype.aether.util.artifact.DefaultArtifact;
import org.sonatype.aether.util.artifact.JavaScopes;
import org.sonatype.aether.util.filter.DependencyFilterUtils;
import org.sonatype.aether.util.filter.PatternExclusionsDependencyFilter;
import org.sonatype.aether.util.graph.DefaultDependencyNode;
/**
@ -157,11 +159,11 @@ public class DependencyResolver extends AbstractDependencyResolver {
*/
@Override
public List<ArtifactResult> getArtifactsWithDep(String dependency,
Collection<String> excludes) throws RepositoryException {
Collection<String> excludes) throws RepositoryException {
Artifact artifact = new DefaultArtifact(dependency);
DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE);
PatternExclusionsDependencyFilter exclusionFilter =
new PatternExclusionsDependencyFilter(excludes);
new PatternExclusionsDependencyFilter(excludes);
CollectRequest collectRequest = new CollectRequest();
collectRequest.setRoot(new Dependency(artifact, JavaScopes.COMPILE));
@ -172,7 +174,11 @@ public class DependencyResolver extends AbstractDependencyResolver {
}
}
DependencyRequest dependencyRequest = new DependencyRequest(collectRequest,
DependencyFilterUtils.andFilter(exclusionFilter, classpathFilter));
return system.resolveDependencies(session, dependencyRequest).getArtifactResults();
DependencyFilterUtils.andFilter(exclusionFilter, classpathFilter));
try {
return system.resolveDependencies(session, dependencyRequest).getArtifactResults();
} catch (NullPointerException ex) {
throw new RepositoryException(String.format("Cannot fetch dependencies for %s", dependency));
}
}
}

View file

@ -16,7 +16,11 @@
*/
package org.apache.zeppelin.dep;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import org.sonatype.aether.repository.Authentication;
import org.sonatype.aether.repository.Proxy;
/**
*
*
@ -27,6 +31,11 @@ public class Repository {
private String url;
private String username = null;
private String password = null;
private String proxyProtocol = "HTTP";
private String proxyHost = null;
private Integer proxyPort = null;
private String proxyLogin = null;
private String proxyPassword = null;
public Repository(String id){
this.id = id;
@ -77,4 +86,16 @@ public class Repository {
}
return auth;
}
public Proxy getProxy() {
if (isNotBlank(proxyHost) && proxyPort != null) {
if (isNotBlank(proxyLogin)) {
return new Proxy(proxyProtocol, proxyHost, proxyPort,
new Authentication(proxyLogin, proxyPassword));
} else {
return new Proxy(proxyProtocol, proxyHost, proxyPort, null);
}
}
return null;
}
}

View file

@ -20,6 +20,7 @@ package org.apache.zeppelin.dep;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Collections;
import org.apache.commons.io.FileUtils;
@ -36,6 +37,9 @@ public class DependencyResolverTest {
private static File testCopyPath;
private static File tmpDir;
@Rule
public ExpectedException expectedException = ExpectedException.none();
@BeforeClass
public static void setUp() throws Exception {
tmpDir = new File(System.getProperty("java.io.tmpdir")+"/ZeppelinLTest_"+System.currentTimeMillis());
@ -90,4 +94,13 @@ public class DependencyResolverTest {
exception.expect(RepositoryException.class);
resolver.load("com.agimatec:agimatec-validation:0.9.3", testCopyPath);
}
@Test
public void should_throw_exception_if_dependency_not_found() throws Exception {
expectedException.expectMessage("Source 'one.two:1.0' does not exist");
expectedException.expect(FileNotFoundException.class);
resolver.load("one.two:1.0", testCopyPath);
}
}

View file

@ -36,7 +36,6 @@ import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.zeppelin.rest.message.RestartInterpreterRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.aether.RepositoryException;
import org.sonatype.aether.repository.RemoteRepository;
import org.apache.zeppelin.annotation.ZeppelinApi;
@ -74,9 +73,7 @@ public class InterpreterRestApi {
@Path("setting")
@ZeppelinApi
public Response listSettings() {
List<InterpreterSetting> interpreterSettings;
interpreterSettings = interpreterFactory.get();
return new JsonResponse<>(Status.OK, "", interpreterSettings).build();
return new JsonResponse<>(Status.OK, "", interpreterFactory.get()).build();
}
/**
@ -208,7 +205,7 @@ public class InterpreterRestApi {
try {
Repository request = gson.fromJson(message, Repository.class);
interpreterFactory.addRepository(request.getId(), request.getUrl(), request.isSnapshot(),
request.getAuthentication());
request.getAuthentication(), request.getProxy());
logger.info("New repository {} added", request.getId());
} catch (Exception e) {
logger.error("Exception in InterpreterRestApi while adding repository ", e);

View file

@ -174,29 +174,24 @@ public class ZeppelinServer extends Application {
ServerConnector connector;
if (conf.useSsl()) {
HttpConfiguration httpConfig = new HttpConfiguration();
httpConfig.setSecureScheme("https");
httpConfig.setSecurePort(conf.getServerPort());
httpConfig.setSecurePort(conf.getServerSslPort());
httpConfig.setOutputBufferSize(32768);
HttpConfiguration httpsConfig = new HttpConfiguration(httpConfig);
SecureRequestCustomizer src = new SecureRequestCustomizer();
// Only with Jetty 9.3.x
// src.setStsMaxAge(2000);
// src.setStsIncludeSubDomains(true);
// src.setStsMaxAge(2000);
// src.setStsIncludeSubDomains(true);
httpsConfig.addCustomizer(src);
connector = new ServerConnector(
server,
new SslConnectionFactory(getSslContextFactory(conf), HttpVersion.HTTP_1_1.asString()),
new HttpConnectionFactory(httpsConfig));
} else {
connector = new ServerConnector(server);
}
// Set some timeout options to make debugging easier.

View file

@ -22,6 +22,7 @@ import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
import org.apache.zeppelin.conf.ZeppelinConfiguration.ConfVars;
import org.apache.zeppelin.display.AngularObject;
@ -1147,7 +1148,18 @@ public class NotebookServer extends WebSocketServlet implements
}
AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal);
note.persist(subject);
try {
note.persist(subject);
} catch (FileSystemException ex) {
LOG.error("Exception from run", ex);
conn.send(serializeMessage(new Message(OP.ERROR_INFO).put("info",
"Oops! There is something wrong with the notebook file system. "
+ "Please check the logs for more details.")));
// don't run the paragraph when there is error on persisting the note information
return;
}
try {
note.run(paragraphId);
} catch (Exception ex) {
@ -1583,9 +1595,11 @@ public class NotebookServer extends WebSocketServlet implements
private void getEditorSetting(NotebookSocket conn, Message fromMessage)
throws IOException {
String paragraphId = (String) fromMessage.get("paragraphId");
String replName = (String) fromMessage.get("magic");
String noteId = getOpenNoteId(conn);
Message resp = new Message(OP.EDITOR_SETTING);
resp.put("paragraphId", paragraphId);
resp.put("editor", notebook().getInterpreterFactory().getEditorSetting(noteId, replName));
conn.send(serializeMessage(resp));
return;

View file

@ -65,7 +65,7 @@ public class NotebookSocket extends WebSocketAdapter {
return protocol;
}
public void send(String serializeMessage) throws IOException {
public synchronized void send(String serializeMessage) throws IOException {
connection.getRemote().sendString(serializeMessage);
}

View file

@ -10,7 +10,7 @@
"autoprefixer": "^6.1.0",
"bower": "1.7.2",
"grunt": "^0.4.1",
"grunt-cache-bust": "^1.3.0",
"grunt-cache-bust": "1.3.0",
"grunt-cli": "^0.1.13",
"grunt-concurrent": "^0.5.0",
"grunt-contrib-clean": "^0.5.0",

View file

@ -12,45 +12,52 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('MainCtrl', function($scope, $rootScope, $window, arrayOrderingSrv) {
$scope.looknfeel = 'default';
angular.module('zeppelinWebApp').controller('MainCtrl', MainCtrl);
var init = function() {
$scope.asIframe = (($window.location.href.indexOf('asIframe') > -1) ? true : false);
};
MainCtrl.$inject = ['$scope', '$rootScope', '$window', 'arrayOrderingSrv'];
init();
function MainCtrl($scope, $rootScope, $window, arrayOrderingSrv) {
$scope.looknfeel = 'default';
$rootScope.$on('setIframe', function(event, data) {
if (!event.defaultPrevented) {
$scope.asIframe = data;
event.preventDefault();
}
});
var init = function() {
$scope.asIframe = (($window.location.href.indexOf('asIframe') > -1) ? true : false);
};
$rootScope.$on('setLookAndFeel', function(event, data) {
if (!event.defaultPrevented && data && data !== '' && data !== $scope.looknfeel) {
$scope.looknfeel = data;
event.preventDefault();
}
});
init();
// Set The lookAndFeel to default on every page
$rootScope.$on('$routeChangeStart', function(event, next, current) {
$rootScope.$broadcast('setLookAndFeel', 'default');
});
$rootScope.$on('setIframe', function(event, data) {
if (!event.defaultPrevented) {
$scope.asIframe = data;
event.preventDefault();
}
});
$rootScope.noteName = function(note) {
if (!_.isEmpty(note)) {
return arrayOrderingSrv.getNoteName(note);
}
};
$rootScope.$on('setLookAndFeel', function(event, data) {
if (!event.defaultPrevented && data && data !== '' && data !== $scope.looknfeel) {
$scope.looknfeel = data;
event.preventDefault();
}
});
BootstrapDialog.defaultOptions.onshown = function() {
angular.element('#' + this.id).find('.btn:last').focus();
};
// Set The lookAndFeel to default on every page
$rootScope.$on('$routeChangeStart', function(event, next, current) {
$rootScope.$broadcast('setLookAndFeel', 'default');
});
// Remove BootstrapDialog animation
BootstrapDialog.configDefaultOptions({animate: false});
});
$rootScope.noteName = function(note) {
if (!_.isEmpty(note)) {
return arrayOrderingSrv.getNoteName(note);
}
};
BootstrapDialog.defaultOptions.onshown = function() {
angular.element('#' + this.id).find('.btn:last').focus();
};
// Remove BootstrapDialog animation
BootstrapDialog.configDefaultOptions({animate: false});
}
})();

View file

@ -90,6 +90,7 @@
ngToastProvider.configure({
dismissButton: true,
dismissOnClick: false,
combineDuplications: true,
timeout: 6000
});
});

View file

@ -11,36 +11,42 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('ConfigurationCtrl', function($scope, $rootScope, $http,
baseUrlSrv, ngToast) {
$scope.configrations = [];
$scope._ = _;
angular.module('zeppelinWebApp').controller('ConfigurationCtrl', ConfigurationCtrl);
var getConfigurations = function() {
$http.get(baseUrlSrv.getRestApiBase() + '/configurations/all').
success(function(data, status, headers, config) {
$scope.configurations = data.body;
}).
error(function(data, status, headers, config) {
if (status === 401) {
ngToast.danger({
content: 'You don\'t have permission on this page',
verticalPosition: 'bottom',
timeout: '3000'
});
setTimeout(function() {
window.location.replace('/');
}, 3000);
}
console.log('Error %o %o', status, data.message);
});
};
ConfigurationCtrl.$inject = ['$scope', '$rootScope', '$http', 'baseUrlSrv', 'ngToast'];
var init = function() {
getConfigurations();
};
function ConfigurationCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) {
$scope.configrations = [];
$scope._ = _;
ngToast.dismiss();
init();
});
var getConfigurations = function() {
$http.get(baseUrlSrv.getRestApiBase() + '/configurations/all').
success(function(data, status, headers, config) {
$scope.configurations = data.body;
}).
error(function(data, status, headers, config) {
if (status === 401) {
ngToast.danger({
content: 'You don\'t have permission on this page',
verticalPosition: 'bottom',
timeout: '3000'
});
setTimeout(function() {
window.location.replace('/');
}, 3000);
}
console.log('Error %o %o', status, data.message);
});
};
var init = function() {
getConfigurations();
};
init();
}
})();

View file

@ -12,145 +12,153 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('CredentialCtrl', function($scope, $rootScope, $http, baseUrlSrv, ngToast) {
$scope._ = _;
angular.module('zeppelinWebApp').controller('CredentialCtrl', CredentialCtrl);
$scope.credentialInfo = [];
$scope.showAddNewCredentialInfo = false;
CredentialCtrl.$inject = ['$scope', '$rootScope', '$http', 'baseUrlSrv', 'ngToast'];
var getCredentialInfo = function() {
$http.get(baseUrlSrv.getRestApiBase() + '/credential').
success(function(data, status, headers, config) {
$scope.credentialInfo = _.map(data.body.userCredentials, function(value, prop) {
return {entity: prop, password: value.password, username: value.username};
function CredentialCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) {
$scope._ = _;
ngToast.dismiss();
$scope.credentialInfo = [];
$scope.showAddNewCredentialInfo = false;
var getCredentialInfo = function() {
$http.get(baseUrlSrv.getRestApiBase() + '/credential').
success(function(data, status, headers, config) {
$scope.credentialInfo = _.map(data.body.userCredentials, function(value, prop) {
return {entity: prop, password: value.password, username: value.username};
});
console.log('Success %o %o', status, $scope.credentialInfo);
}).
error(function(data, status, headers, config) {
if (status === 401) {
ngToast.danger({
content: 'You don\'t have permission on this page',
verticalPosition: 'bottom',
timeout: '3000'
});
setTimeout(function() {
window.location.replace('/');
}, 3000);
}
console.log('Error %o %o', status, data.message);
});
console.log('Success %o %o', status, $scope.credentialInfo);
}).
error(function(data, status, headers, config) {
if (status === 401) {
};
$scope.addNewCredentialInfo = function() {
if ($scope.entity && _.isEmpty($scope.entity.trim()) &&
$scope.username && _.isEmpty($scope.username.trim())) {
ngToast.danger({
content: 'You don\'t have permission on this page',
content: 'Username \\ Entity can not be empty.',
verticalPosition: 'bottom',
timeout: '3000'
});
setTimeout(function() {
window.location.replace('/');
}, 3000);
return;
}
console.log('Error %o %o', status, data.message);
});
};
$scope.addNewCredentialInfo = function() {
if ($scope.entity && _.isEmpty($scope.entity.trim()) &&
$scope.username && _.isEmpty($scope.username.trim())) {
ngToast.danger({
content: 'Username \\ Entity can not be empty.',
verticalPosition: 'bottom',
timeout: '3000'
var newCredential = {
'entity': $scope.entity,
'username': $scope.username,
'password': $scope.password
};
$http.put(baseUrlSrv.getRestApiBase() + '/credential', newCredential).
success(function(data, status, headers, config) {
ngToast.success({
content: 'Successfully saved credentials.',
verticalPosition: 'bottom',
timeout: '3000'
});
$scope.credentialInfo.push(newCredential);
resetCredentialInfo();
$scope.showAddNewCredentialInfo = false;
console.log('Success %o %o', status, data.message);
}).
error(function(data, status, headers, config) {
ngToast.danger({
content: 'Error saving credentials',
verticalPosition: 'bottom',
timeout: '3000'
});
console.log('Error %o %o', status, data.message);
});
return;
}
var newCredential = {
'entity': $scope.entity,
'username': $scope.username,
'password': $scope.password
};
$http.put(baseUrlSrv.getRestApiBase() + '/credential', newCredential).
success(function(data, status, headers, config) {
ngToast.success({
content: 'Successfully saved credentials.',
verticalPosition: 'bottom',
timeout: '3000'
});
$scope.credentialInfo.push(newCredential);
resetCredentialInfo();
$scope.cancelCredentialInfo = function() {
$scope.showAddNewCredentialInfo = false;
console.log('Success %o %o', status, data.message);
}).
error(function(data, status, headers, config) {
ngToast.danger({
content: 'Error saving credentials',
verticalPosition: 'bottom',
timeout: '3000'
});
console.log('Error %o %o', status, data.message);
});
};
$scope.cancelCredentialInfo = function() {
$scope.showAddNewCredentialInfo = false;
resetCredentialInfo();
};
var resetCredentialInfo = function() {
$scope.entity = '';
$scope.username = '';
$scope.password = '';
};
$scope.copyOriginCredentialsInfo = function() {
ngToast.info({
content: 'Since entity is a unique key, you can edit only username & password',
verticalPosition: 'bottom',
timeout: '3000'
});
};
$scope.updateCredentialInfo = function(form, data, entity) {
var request = {
entity: entity,
username: data.username,
password: data.password
resetCredentialInfo();
};
$http.put(baseUrlSrv.getRestApiBase() + '/credential/', request).
success(function(data, status, headers, config) {
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
$scope.credentialInfo[index] = request;
return true;
}).
error(function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
ngToast.danger({
content: 'We couldn\'t save the credential',
var resetCredentialInfo = function() {
$scope.entity = '';
$scope.username = '';
$scope.password = '';
};
$scope.copyOriginCredentialsInfo = function() {
ngToast.info({
content: 'Since entity is a unique key, you can edit only username & password',
verticalPosition: 'bottom',
timeout: '3000'
});
form.$show();
});
return false;
};
};
$scope.removeCredentialInfo = function(entity) {
BootstrapDialog.confirm({
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
title: '',
message: 'Do you want to delete this credential information?',
callback: function(result) {
if (result) {
$http.delete(baseUrlSrv.getRestApiBase() + '/credential/' + entity).
success(function(data, status, headers, config) {
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
$scope.credentialInfo.splice(index, 1);
console.log('Success %o %o', status, data.message);
}).
error(function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
});
$scope.updateCredentialInfo = function(form, data, entity) {
var request = {
entity: entity,
username: data.username,
password: data.password
};
$http.put(baseUrlSrv.getRestApiBase() + '/credential/', request).
success(function(data, status, headers, config) {
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
$scope.credentialInfo[index] = request;
return true;
}).
error(function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
ngToast.danger({
content: 'We couldn\'t save the credential',
verticalPosition: 'bottom',
timeout: '3000'
});
form.$show();
});
return false;
};
$scope.removeCredentialInfo = function(entity) {
BootstrapDialog.confirm({
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
title: '',
message: 'Do you want to delete this credential information?',
callback: function(result) {
if (result) {
$http.delete(baseUrlSrv.getRestApiBase() + '/credential/' + entity).
success(function(data, status, headers, config) {
var index = _.findIndex($scope.credentialInfo, {'entity': entity});
$scope.credentialInfo.splice(index, 1);
console.log('Success %o %o', status, data.message);
}).
error(function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
});
}
}
}
});
};
});
};
var init = function() {
getCredentialInfo();
};
var init = function() {
getCredentialInfo();
};
init();
});
init();
}
})();

View file

@ -12,66 +12,79 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('HomeCtrl', function($scope, notebookListDataFactory, websocketMsgSrv,
$rootScope, arrayOrderingSrv) {
var vm = this;
vm.notes = notebookListDataFactory;
vm.websocketMsgSrv = websocketMsgSrv;
vm.arrayOrderingSrv = arrayOrderingSrv;
angular.module('zeppelinWebApp').controller('HomeCtrl', HomeCtrl);
vm.notebookHome = false;
if ($rootScope.ticket !== undefined) {
vm.staticHome = false;
} else {
vm.staticHome = true;
}
HomeCtrl.$inject = [
'$scope',
'notebookListDataFactory',
'websocketMsgSrv',
'$rootScope',
'arrayOrderingSrv',
'ngToast'
];
$scope.isReloading = false;
function HomeCtrl($scope, notebookListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv, ngToast) {
ngToast.dismiss();
var vm = this;
vm.notes = notebookListDataFactory;
vm.websocketMsgSrv = websocketMsgSrv;
vm.arrayOrderingSrv = arrayOrderingSrv;
var initHome = function() {
websocketMsgSrv.getHomeNotebook();
};
initHome();
$scope.reloadNotebookList = function() {
websocketMsgSrv.reloadAllNotesFromRepo();
$scope.isReloadingNotes = true;
};
$scope.toggleFolderNode = function(node) {
node.hidden = !node.hidden;
};
angular.element('#loginModal').on('hidden.bs.modal', function(e) {
$rootScope.$broadcast('initLoginValues');
});
/*
** $scope.$on functions below
*/
$scope.$on('setNoteMenu', function(event, notes) {
$scope.isReloadingNotes = false;
});
$scope.$on('setNoteContent', function(event, note) {
if (note) {
vm.note = note;
// initialize look And Feel
$rootScope.$broadcast('setLookAndFeel', 'home');
// make it read only
vm.viewOnly = true;
vm.notebookHome = true;
vm.notebookHome = false;
if ($rootScope.ticket !== undefined) {
vm.staticHome = false;
} else {
vm.staticHome = true;
vm.notebookHome = false;
}
});
});
$scope.isReloading = false;
var initHome = function() {
websocketMsgSrv.getHomeNotebook();
};
initHome();
$scope.reloadNotebookList = function() {
websocketMsgSrv.reloadAllNotesFromRepo();
$scope.isReloadingNotes = true;
};
$scope.toggleFolderNode = function(node) {
node.hidden = !node.hidden;
};
angular.element('#loginModal').on('hidden.bs.modal', function(e) {
$rootScope.$broadcast('initLoginValues');
});
/*
** $scope.$on functions below
*/
$scope.$on('setNoteMenu', function(event, notes) {
$scope.isReloadingNotes = false;
});
$scope.$on('setNoteContent', function(event, note) {
if (note) {
vm.note = note;
// initialize look And Feel
$rootScope.$broadcast('setLookAndFeel', 'home');
// make it read only
vm.viewOnly = true;
vm.notebookHome = true;
vm.staticHome = false;
} else {
vm.staticHome = true;
vm.notebookHome = false;
}
});
}
})();

View file

@ -804,24 +804,27 @@ This part should be removed when new version of bootstrap handles this issue.
background: #3071a9;
}
.about{
/* About Zeppelin */
.about {
height: 200px;
padding-top: 20px;
padding-left: 20px;
padding: 25px;
}
.about .logo {
width: 20%;
float: left;
padding-top: 30px;
}
.about .content{
float: left;
padding-left: 10px;
top: -30px;
position: relative;
.about .logo img {
width: 95%;
}
.about .logo img{
width: 100%;
.about .content {
text-align: center;
}
.about .content h3 {
font-family: 'Patua One';
color: #3071A9;
font-size: 30px;
margin: 0 auto;
}

View file

@ -12,15 +12,20 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('InterpreterCtrl',
function($scope, $http, baseUrlSrv, ngToast, $timeout, $route) {
angular.module('zeppelinWebApp').controller('InterpreterCtrl', InterpreterCtrl);
InterpreterCtrl.$inject = ['$scope', '$http', 'baseUrlSrv', 'ngToast', '$timeout', '$route'];
function InterpreterCtrl($scope, $http, baseUrlSrv, ngToast, $timeout, $route) {
var interpreterSettingsTmp = [];
$scope.interpreterSettings = [];
$scope.availableInterpreters = {};
$scope.showAddNewSetting = false;
$scope.showRepositoryInfo = false;
$scope._ = _;
ngToast.dismiss();
$scope.openPermissions = function() {
$scope.showInterpreterAuth = true;
@ -104,12 +109,19 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl',
var checkDownloadingDependencies = function() {
var isDownloading = false;
for (var setting = 0; setting < $scope.interpreterSettings.length; setting++) {
if ($scope.interpreterSettings[setting].status === 'DOWNLOADING_DEPENDENCIES') {
for (var index = 0; index < $scope.interpreterSettings.length; index++) {
var setting = $scope.interpreterSettings[index];
if (setting.status === 'DOWNLOADING_DEPENDENCIES') {
isDownloading = true;
break;
}
if (setting.status === 'ERROR' || setting.errorReason) {
ngToast.danger({content: 'Error setting properties for interpreter \'' +
setting.group + '.' + setting.name + '\': ' + setting.errorReason,
verticalPosition: 'top', dismissOnTimeout: false});
}
}
if (isDownloading) {
$timeout(function() {
if ($route.current.$$route.originalPath === '/interpreter') {
@ -232,7 +244,6 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl',
$scope.interpreterSettings[index] = data.body;
removeTMPSettings(index);
thisConfirm.close();
checkDownloadingDependencies();
$route.reload();
})
.error(function(data, status, headers, config) {
@ -504,7 +515,12 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl',
url: '',
snapshot: false,
username: '',
password: ''
password: '',
proxyProtocol: 'HTTP',
proxyHost: '',
proxyPort: null,
proxyLogin: '',
proxyPassword: ''
};
};
@ -574,4 +590,6 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl',
};
init();
});
}
})();

View file

@ -12,10 +12,15 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').filter('sortByKey', function() {
return function(properties) {
var sortedKeys = properties ? Object.keys(properties) : [];
return sortedKeys.sort();
};
});
angular.module('zeppelinWebApp').filter('sortByKey', sortByKey);
function sortByKey() {
return function(properties) {
var sortedKeys = properties ? Object.keys(properties) : [];
return sortedKeys.sort();
};
}
})();

View file

@ -65,7 +65,9 @@ limitations under the License.
popover-html-unsafe="<label>URL: </label>
{{repo.url}}<br>
<label>Username: </label>
{{repo.authentication.username}}">
{{repo.authentication.username}}<br>
<label>Proxy host: </label>
{{repo.proxy.host}}">
<span class="fa fa-database"></span>
{{repo.id}}&nbsp;
<span ng-if="!isDefaultRepository(repo.id)" class="fa fa-close blackOpc"

View file

@ -12,78 +12,83 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp')
.controller('JobmanagerCtrl',
function($scope, websocketMsgSrv, $interval) {
angular.module('zeppelinWebApp').controller('JobmanagerCtrl', JobmanagerCtrl);
$scope.filterValueToName = function(filterValue) {
var index = _.findIndex($scope.ACTIVE_INTERPRETERS, {value: filterValue});
JobmanagerCtrl.$inject = ['$scope', 'websocketMsgSrv', '$interval', 'ngToast'];
if ($scope.ACTIVE_INTERPRETERS[index].name !== undefined) {
return $scope.ACTIVE_INTERPRETERS[index].name;
} else {
return 'undefined';
}
};
function JobmanagerCtrl($scope, websocketMsgSrv, $interval, ngToast) {
ngToast.dismiss();
$scope.filterValueToName = function(filterValue) {
var index = _.findIndex($scope.ACTIVE_INTERPRETERS, {value: filterValue});
$scope.init = function() {
$scope.jobInfomations = [];
$scope.JobInfomationsByFilter = $scope.jobInfomations;
if ($scope.ACTIVE_INTERPRETERS[index].name !== undefined) {
return $scope.ACTIVE_INTERPRETERS[index].name;
} else {
return 'undefined';
}
};
websocketMsgSrv.getNotebookJobsList();
$scope.init = function() {
$scope.jobInfomations = [];
$scope.JobInfomationsByFilter = $scope.jobInfomations;
$scope.$on('$destroy', function() {
websocketMsgSrv.unsubscribeJobManager();
});
};
websocketMsgSrv.getNotebookJobsList();
/*
** $scope.$on functions below
*/
$scope.$on('setNotebookJobs', function(event, responseData) {
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
$scope.jobInfomations = responseData.jobs;
$scope.jobInfomationsIndexs = $scope.jobInfomations ? _.indexBy($scope.jobInfomations, 'notebookId') : {};
$scope.$on('$destroy', function() {
websocketMsgSrv.unsubscribeJobManager();
});
};
$scope.$on('setUpdateNotebookJobs', function(event, responseData) {
var jobInfomations = $scope.jobInfomations;
var indexStore = $scope.jobInfomationsIndexs;
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
var notes = responseData.jobs;
notes.map(function(changedItem) {
if (indexStore[changedItem.notebookId] === undefined) {
var newItem = angular.copy(changedItem);
jobInfomations.push(newItem);
indexStore[changedItem.notebookId] = newItem;
} else {
var changeOriginTarget = indexStore[changedItem.notebookId];
/*
** $scope.$on functions below
*/
if (changedItem.isRemoved !== undefined && changedItem.isRemoved === true) {
$scope.$on('setNotebookJobs', function(event, responseData) {
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
$scope.jobInfomations = responseData.jobs;
$scope.jobInfomationsIndexs = $scope.jobInfomations ? _.indexBy($scope.jobInfomations, 'notebookId') : {};
});
// remove Item.
var removeIndex = _.findIndex(indexStore, changedItem.notebookId);
if (removeIndex > -1) {
indexStore.splice(removeIndex, 1);
}
$scope.$on('setUpdateNotebookJobs', function(event, responseData) {
var jobInfomations = $scope.jobInfomations;
var indexStore = $scope.jobInfomationsIndexs;
$scope.lastJobServerUnixTime = responseData.lastResponseUnixTime;
var notes = responseData.jobs;
notes.map(function(changedItem) {
if (indexStore[changedItem.notebookId] === undefined) {
var newItem = angular.copy(changedItem);
jobInfomations.push(newItem);
indexStore[changedItem.notebookId] = newItem;
} else {
var changeOriginTarget = indexStore[changedItem.notebookId];
removeIndex = _.findIndex(jobInfomations, {'notebookId': changedItem.notebookId});
if (removeIndex) {
jobInfomations.splice(removeIndex, 1);
}
if (changedItem.isRemoved !== undefined && changedItem.isRemoved === true) {
} else {
// change value for item.
changeOriginTarget.isRunningJob = changedItem.isRunningJob;
changeOriginTarget.notebookName = changedItem.notebookName;
changeOriginTarget.notebookType = changedItem.notebookType;
changeOriginTarget.interpreter = changedItem.interpreter;
changeOriginTarget.unixTimeLastRun = changedItem.unixTimeLastRun;
changeOriginTarget.paragraphs = changedItem.paragraphs;
// remove Item.
var removeIndex = _.findIndex(indexStore, changedItem.notebookId);
if (removeIndex > -1) {
indexStore.splice(removeIndex, 1);
}
removeIndex = _.findIndex(jobInfomations, {'notebookId': changedItem.notebookId});
if (removeIndex) {
jobInfomations.splice(removeIndex, 1);
}
} else {
// change value for item.
changeOriginTarget.isRunningJob = changedItem.isRunningJob;
changeOriginTarget.notebookName = changedItem.notebookName;
changeOriginTarget.notebookType = changedItem.notebookType;
changeOriginTarget.interpreter = changedItem.interpreter;
changeOriginTarget.unixTimeLastRun = changedItem.unixTimeLastRun;
changeOriginTarget.paragraphs = changedItem.paragraphs;
}
});
}
});
});
}
})();

View file

@ -12,10 +12,13 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp')
.controller('JobCtrl', function($scope) {
angular.module('zeppelinWebApp').controller('JobCtrl', JobCtrl);
JobCtrl.$inject = ['$scope'];
function JobCtrl($scope) {
$scope.init = function(jobInformation) {
$scope.progressValue = 0;
};
@ -34,5 +37,6 @@ angular.module('zeppelinWebApp')
var result = Math.ceil(runningJobCount / totalCount * 100);
return isNaN(result) ? 0 : result;
};
}
});
})();

View file

@ -53,7 +53,7 @@ limitations under the License.
<button type="button"
class="btn btn-default btn-xs"
ng-hide="viewOnly"
tooltip-placement="bottom" tooltip="Clone the notebook"
tooltip-placement="bottom" tooltip="Clone the notebook" data-source-note-name="{{note.name}}"
data-toggle="modal" data-target="#noteNameModal" data-clone="true"
>
<i class="fa fa-copy"></i>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -12,11 +12,13 @@
* limitations under the License.
*/
'use strict';
(function() {
angular
.module('zeppelinWebApp')
.controller('SearchResultCtrl', function($scope, $routeParams, searchService) {
angular.module('zeppelinWebApp').controller('SearchResultCtrl', SearchResultCtrl);
SearchResultCtrl.$inject = ['$scope', '$routeParams', 'searchService'];
function SearchResultCtrl($scope, $routeParams, searchService) {
$scope.isResult = true ;
$scope.searchTerm = $routeParams.searchTerm;
var results = searchService.search({'q': $routeParams.searchTerm}).query();
@ -152,4 +154,6 @@ angular
};
};
});
}
})();

View file

@ -12,21 +12,24 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').service('arrayOrderingSrv', function() {
angular.module('zeppelinWebApp').service('arrayOrderingSrv', arrayOrderingSrv);
var arrayOrderingSrv = this;
function arrayOrderingSrv() {
var arrayOrderingSrv = this;
this.notebookListOrdering = function(note) {
return arrayOrderingSrv.getNoteName(note);
};
this.notebookListOrdering = function(note) {
return arrayOrderingSrv.getNoteName(note);
};
this.getNoteName = function(note) {
if (note.name === undefined || note.name.trim() === '') {
return 'Note ' + note.id;
} else {
return note.name;
}
};
this.getNoteName = function(note) {
if (note.name === undefined || note.name.trim() === '') {
return 'Note ' + note.id;
} else {
return note.name;
}
};
}
});
})();

View file

@ -12,36 +12,41 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').service('baseUrlSrv', function() {
angular.module('zeppelinWebApp').service('baseUrlSrv', baseUrlSrv);
this.getPort = function() {
var port = Number(location.port);
if (!port) {
port = 80;
if (location.protocol === 'https:') {
port = 443;
function baseUrlSrv() {
this.getPort = function() {
var port = Number(location.port);
if (!port) {
port = 80;
if (location.protocol === 'https:') {
port = 443;
}
}
}
//Exception for when running locally via grunt
if (port === 3333 || port === 9000) {
port = 8080;
}
return port;
};
//Exception for when running locally via grunt
if (port === 3333 || port === 9000) {
port = 8080;
}
return port;
};
this.getWebsocketUrl = function() {
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
return wsProtocol + '//' + location.hostname + ':' + this.getPort() + skipTrailingSlash(location.pathname) + '/ws';
};
this.getWebsocketUrl = function() {
var wsProtocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
return wsProtocol + '//' + location.hostname + ':' + this.getPort() +
skipTrailingSlash(location.pathname) + '/ws';
};
this.getRestApiBase = function() {
return location.protocol + '//' + location.hostname + ':' + this.getPort() + skipTrailingSlash(location.pathname) +
'/api';
};
this.getRestApiBase = function() {
return location.protocol + '//' + location.hostname + ':' +
this.getPort() + skipTrailingSlash(location.pathname) +
'/api';
};
var skipTrailingSlash = function(path) {
return path.replace(/\/$/, '');
};
var skipTrailingSlash = function(path) {
return path.replace(/\/$/, '');
};
}
});
})();

View file

@ -12,29 +12,32 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').service('browserDetectService', function() {
angular.module('zeppelinWebApp').service('browserDetectService', browserDetectService);
this.detectIE = function() {
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE ');
if (msie > 0) {
// IE 10 or older => return version number
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
}
var trident = ua.indexOf('Trident/');
if (trident > 0) {
// IE 11 => return version number
var rv = ua.indexOf('rv:');
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
}
var edge = ua.indexOf('Edge/');
if (edge > 0) {
// IE 12 (aka Edge) => return version number
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
}
// other browser
return false;
};
function browserDetectService() {
this.detectIE = function() {
var ua = window.navigator.userAgent;
var msie = ua.indexOf('MSIE ');
if (msie > 0) {
// IE 10 or older => return version number
return parseInt(ua.substring(msie + 5, ua.indexOf('.', msie)), 10);
}
var trident = ua.indexOf('Trident/');
if (trident > 0) {
// IE 11 => return version number
var rv = ua.indexOf('rv:');
return parseInt(ua.substring(rv + 3, ua.indexOf('.', rv)), 10);
}
var edge = ua.indexOf('Edge/');
if (edge > 0) {
// IE 12 (aka Edge) => return version number
return parseInt(ua.substring(edge + 5, ua.indexOf('.', edge)), 10);
}
// other browser
return false;
};
}
});
})();

View file

@ -12,14 +12,19 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('dropdownInput', function() {
return {
restrict: 'A',
link: function(scope, element) {
element.bind('click', function(event) {
event.stopPropagation();
});
}
};
});
angular.module('zeppelinWebApp').directive('dropdownInput', dropdownInput);
function dropdownInput() {
return {
restrict: 'A',
link: function(scope, element) {
element.bind('click', function(event) {
event.stopPropagation();
});
}
};
}
})();

View file

@ -12,9 +12,13 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp')
.controller('ElasticInputCtrl', function() {
var vm = this;
vm.showEditor = false;
});
angular.module('zeppelinWebApp').controller('ElasticInputCtrl', ElasticInputCtrl);
function ElasticInputCtrl() {
var vm = this;
vm.showEditor = false;
}
})();

View file

@ -12,22 +12,27 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('expandCollapse', function() {
return {
restrict: 'EA',
link: function(scope, element, attrs) {
angular.element(element).click(function(event) {
if (angular.element(element).find('.expandable:visible').length > 1) {
angular.element(element).find('.expandable:visible').slideUp('slow');
angular.element(element).find('i.icon-folder-alt').toggleClass('icon-folder icon-folder-alt');
} else {
angular.element(element).find('.expandable').first().slideToggle('200',function() {
angular.element(element).find('i').first().toggleClass('icon-folder icon-folder-alt');
});
}
event.stopPropagation();
angular.module('zeppelinWebApp').directive('expandCollapse', expandCollapse);
function expandCollapse() {
return {
restrict: 'EA',
link: function(scope, element, attrs) {
angular.element(element).click(function(event) {
if (angular.element(element).find('.expandable:visible').length > 1) {
angular.element(element).find('.expandable:visible').slideUp('slow');
angular.element(element).find('i.icon-folder-alt').toggleClass('icon-folder icon-folder-alt');
} else {
angular.element(element).find('.expandable').first().slideToggle('200',function() {
angular.element(element).find('i').first().toggleClass('icon-folder icon-folder-alt');
});
}
};
});
event.stopPropagation();
});
}
};
}
})();

View file

@ -12,17 +12,24 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('interpreterDirective', function($timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
if (scope.$last === true) {
$timeout(function() {
var id = 'ngRenderFinished';
scope.$emit(id);
});
angular.module('zeppelinWebApp').directive('interpreterDirective', interpreterDirective);
interpreterDirective.$inject = ['$timeout'];
function interpreterDirective($timeout) {
return {
restrict: 'A',
link: function(scope, element, attr) {
if (scope.$last === true) {
$timeout(function() {
var id = 'ngRenderFinished';
scope.$emit(id);
});
}
}
}
};
});
};
}
})();

View file

@ -11,11 +11,14 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('LoginCtrl',
function($scope, $rootScope, $http, $httpParamSerializer, baseUrlSrv) {
angular.module('zeppelinWebApp').controller('LoginCtrl', LoginCtrl);
LoginCtrl.$inject = ['$scope', '$rootScope', '$http', '$httpParamSerializer', 'baseUrlSrv'];
function LoginCtrl($scope, $rootScope, $http, $httpParamSerializer, baseUrlSrv) {
$scope.loginParams = {};
$scope.login = function() {
@ -55,4 +58,5 @@ angular.module('zeppelinWebApp').controller('LoginCtrl',
initValues();
});
}
);
})();

View file

@ -11,102 +11,117 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp')
.controller('NavCtrl', function($scope, $rootScope, $http, $routeParams,
$location, notebookListDataFactory, baseUrlSrv, websocketMsgSrv, arrayOrderingSrv, searchService) {
angular.module('zeppelinWebApp').controller('NavCtrl', NavCtrl);
var vm = this;
vm.arrayOrderingSrv = arrayOrderingSrv;
vm.connected = websocketMsgSrv.isConnected();
vm.isActive = isActive;
vm.logout = logout;
vm.notes = notebookListDataFactory;
vm.search = search;
vm.searchForm = searchService;
vm.showLoginWindow = showLoginWindow;
NavCtrl.$inject = [
'$scope',
'$rootScope',
'$http',
'$routeParams',
'$location',
'notebookListDataFactory',
'baseUrlSrv',
'websocketMsgSrv',
'arrayOrderingSrv',
'searchService'
];
$scope.query = {q: ''};
function NavCtrl($scope, $rootScope, $http, $routeParams, $location,
notebookListDataFactory, baseUrlSrv, websocketMsgSrv,
arrayOrderingSrv, searchService) {
var vm = this;
vm.arrayOrderingSrv = arrayOrderingSrv;
vm.connected = websocketMsgSrv.isConnected();
vm.isActive = isActive;
vm.logout = logout;
vm.notes = notebookListDataFactory;
vm.search = search;
vm.searchForm = searchService;
vm.showLoginWindow = showLoginWindow;
initController();
$scope.query = {q: ''};
function getZeppelinVersion() {
$http.get(baseUrlSrv.getRestApiBase() + '/version').success(
function(data, status, headers, config) {
$rootScope.zeppelinVersion = data.body;
}).error(
function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
});
}
initController();
function initController() {
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
angular.element(document).click(function() {
$scope.query.q = '';
});
getZeppelinVersion();
loadNotes();
}
function isActive(noteId) {
return ($routeParams.noteId === noteId);
}
function loadNotes() {
websocketMsgSrv.getNotebookList();
}
function logout() {
var logoutURL = baseUrlSrv.getRestApiBase() + '/login/logout';
//for firefox and safari
logoutURL = logoutURL.replace('//', '//false:false@');
$http.post(logoutURL).error(function() {
//force authcBasic (if configured) to logout
$http.post(logoutURL).error(function() {
$rootScope.userName = '';
$rootScope.ticket.principal = '';
$rootScope.ticket.ticket = '';
$rootScope.ticket.roles = '';
BootstrapDialog.show({
message: 'Logout Success'
function getZeppelinVersion() {
$http.get(baseUrlSrv.getRestApiBase() + '/version').success(
function(data, status, headers, config) {
$rootScope.zeppelinVersion = data.body;
}).error(
function(data, status, headers, config) {
console.log('Error %o %o', status, data.message);
});
setTimeout(function() {
window.location.replace('/');
}, 1000);
}
function initController() {
angular.element('#notebook-list').perfectScrollbar({suppressScrollX: true});
angular.element(document).click(function() {
$scope.query.q = '';
});
getZeppelinVersion();
loadNotes();
}
function isActive(noteId) {
return ($routeParams.noteId === noteId);
}
function loadNotes() {
websocketMsgSrv.getNotebookList();
}
function logout() {
var logoutURL = baseUrlSrv.getRestApiBase() + '/login/logout';
//for firefox and safari
logoutURL = logoutURL.replace('//', '//false:false@');
$http.post(logoutURL).error(function() {
//force authcBasic (if configured) to logout
$http.post(logoutURL).error(function() {
$rootScope.userName = '';
$rootScope.ticket.principal = '';
$rootScope.ticket.ticket = '';
$rootScope.ticket.roles = '';
BootstrapDialog.show({
message: 'Logout Success'
});
setTimeout(function() {
window.location.replace('/');
}, 1000);
});
});
}
function search(searchTerm) {
$location.path('/search/' + searchTerm);
}
function showLoginWindow() {
setTimeout(function() {
angular.element('#userName').focus();
}, 500);
}
/*
** $scope.$on functions below
*/
$scope.$on('setNoteMenu', function(event, notes) {
notebookListDataFactory.setNotes(notes);
});
$scope.$on('setConnectedStatus', function(event, param) {
vm.connected = param;
});
$scope.$on('loginSuccess', function(event, param) {
loadNotes();
});
}
function search(searchTerm) {
$location.path('/search/' + searchTerm);
}
function showLoginWindow() {
setTimeout(function() {
angular.element('#userName').focus();
}, 500);
}
/*
** $scope.$on functions below
*/
$scope.$on('setNoteMenu', function(event, notes) {
notebookListDataFactory.setNotes(notes);
});
$scope.$on('setConnectedStatus', function(event, param) {
vm.connected = param;
});
$scope.$on('loginSuccess', function(event, param) {
loadNotes();
});
});
})();

View file

@ -114,11 +114,11 @@ limitations under the License.
</div>
<div class="modal-body">
<div class="about">
<div class="logo">
<div class="row about">
<div class="hidden-xs col-sm-4 col-md-4 logo">
<img src="assets/images/zepLogo.png" alt="Apache Zeppelin" title="Apache Zeppelin" />
</div>
<div class="content">
<div class="col-xs-12 col-sm-8 col-md-8 content">
<h3>Apache Zeppelin</h3>
<br/>
<span id="i18n-14">Version</span>

View file

@ -12,18 +12,23 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('ngEnter', function() {
return function(scope, element, attrs) {
element.bind('keydown keypress', function(event) {
if (event.which === 13) {
if (!event.shiftKey) {
scope.$apply(function() {
scope.$eval(attrs.ngEnter);
});
angular.module('zeppelinWebApp').directive('ngEnter', ngEnter);
function ngEnter() {
return function(scope, element, attrs) {
element.bind('keydown keypress', function(event) {
if (event.which === 13) {
if (!event.shiftKey) {
scope.$apply(function() {
scope.$eval(attrs.ngEnter);
});
}
event.preventDefault();
}
event.preventDefault();
}
});
};
});
});
};
}
})();

View file

@ -12,16 +12,21 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('ngEscape', function() {
return function(scope, element, attrs) {
element.bind('keydown keyup', function(event) {
if (event.which === 27) {
scope.$apply(function() {
scope.$eval(attrs.ngEscape);
});
event.preventDefault();
}
});
};
});
angular.module('zeppelinWebApp').directive('ngEscape', ngEscape);
function ngEscape() {
return function(scope, element, attrs) {
element.bind('keydown keyup', function(event) {
if (event.which === 27) {
scope.$apply(function() {
scope.$eval(attrs.ngEscape);
});
event.preventDefault();
}
});
};
}
})();

View file

@ -11,49 +11,85 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').controller('NotenameCtrl', function($scope, notebookListDataFactory,
$routeParams, websocketMsgSrv) {
var vm = this;
vm.clone = false;
vm.notes = notebookListDataFactory;
vm.websocketMsgSrv = websocketMsgSrv;
$scope.note = {};
angular.module('zeppelinWebApp').controller('NotenameCtrl', NotenameCtrl);
vm.createNote = function() {
if (!vm.clone) {
vm.websocketMsgSrv.createNotebook($scope.note.notename);
} else {
var noteId = $routeParams.noteId;
vm.websocketMsgSrv.cloneNotebook(noteId, $scope.note.notename);
}
};
NotenameCtrl.$inject = [
'$scope',
'notebookListDataFactory',
'$routeParams',
'websocketMsgSrv'
];
vm.handleNameEnter = function() {
angular.element('#noteNameModal').modal('toggle');
vm.createNote();
};
function NotenameCtrl($scope, notebookListDataFactory, $routeParams, websocketMsgSrv) {
var vm = this;
vm.clone = false;
vm.notes = notebookListDataFactory;
vm.websocketMsgSrv = websocketMsgSrv;
$scope.note = {};
vm.preVisible = function(clone) {
$scope.note.notename = vm.newNoteName();
vm.clone = clone;
$scope.$apply();
};
vm.newNoteName = function() {
var newCount = 1;
angular.forEach(vm.notes.flatList, function(noteName) {
noteName = noteName.name;
if (noteName.match(/^Untitled Note [0-9]*$/)) {
var lastCount = noteName.substr(14) * 1;
if (newCount <= lastCount) {
newCount = lastCount + 1;
}
vm.createNote = function() {
if (!vm.clone) {
vm.websocketMsgSrv.createNotebook($scope.note.notename);
} else {
var noteId = $routeParams.noteId;
vm.websocketMsgSrv.cloneNotebook(noteId, $scope.note.notename);
}
});
return 'Untitled Note ' + newCount;
};
};
});
vm.handleNameEnter = function() {
angular.element('#noteNameModal').modal('toggle');
vm.createNote();
};
vm.preVisible = function(clone, sourceNoteName) {
vm.clone = clone;
vm.sourceNoteName = sourceNoteName;
$scope.note.notename = vm.clone ? vm.cloneNoteName() : vm.newNoteName();
$scope.$apply();
};
vm.newNoteName = function() {
var newCount = 1;
angular.forEach(vm.notes.flatList, function(noteName) {
noteName = noteName.name;
if (noteName.match(/^Untitled Note [0-9]*$/)) {
var lastCount = noteName.substr(14) * 1;
if (newCount <= lastCount) {
newCount = lastCount + 1;
}
}
});
return 'Untitled Note ' + newCount;
};
vm.cloneNoteName = function() {
var copyCount = 1;
var newCloneName = '';
var lastIndex = vm.sourceNoteName.lastIndexOf(' ');
var endsWithNumber = !!vm.sourceNoteName.match('^.+?\\s\\d$');
var noteNamePrefix = endsWithNumber ? vm.sourceNoteName.substr(0, lastIndex) : vm.sourceNoteName;
var regexp = new RegExp('^' + noteNamePrefix + ' .+');
angular.forEach(vm.notes.flatList, function(noteName) {
noteName = noteName.name;
if (noteName.match(regexp)) {
var lastCopyCount = noteName.substr(lastIndex).trim();
newCloneName = noteNamePrefix;
lastCopyCount = parseInt(lastCopyCount);
if (copyCount <= lastCopyCount) {
copyCount = lastCopyCount + 1;
}
}
});
if (!newCloneName) {
newCloneName = vm.sourceNoteName;
}
return newCloneName + ' ' + copyCount;
};
}
})();

View file

@ -12,31 +12,37 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('modalvisible', function() {
return {
restrict: 'A',
scope: {
preVisibleCallback: '&previsiblecallback',
postVisibleCallback: '&postvisiblecallback',
targetinput: '@targetinput'
},
link: function(scope, elem, attrs) {
// Add some listeners
var previsibleMethod = scope.preVisibleCallback;
var postVisibleMethod = scope.postVisibleCallback;
elem.on('show.bs.modal',function(e) {
var relatedTgt = angular.element(e.relatedTarget);
var clone = relatedTgt.data('clone');
var cloneNote = clone ? true : false;
previsibleMethod()(cloneNote);
});
elem.on('shown.bs.modal', function(e) {
if (scope.targetinput) {
angular.element(e.target).find('input#' + scope.targetinput).select();
}
postVisibleMethod();
});
}
};
});
angular.module('zeppelinWebApp').directive('modalvisible', modalvisible);
function modalvisible() {
return {
restrict: 'A',
scope: {
preVisibleCallback: '&previsiblecallback',
postVisibleCallback: '&postvisiblecallback',
targetinput: '@targetinput'
},
link: function(scope, element, attrs) {
// Add some listeners
var previsibleMethod = scope.preVisibleCallback;
var postVisibleMethod = scope.postVisibleCallback;
element.on('show.bs.modal',function(e) {
var relatedTarget = angular.element(e.relatedTarget);
var clone = relatedTarget.data('clone');
var sourceNoteName = relatedTarget.data('source-note-name');
var cloneNote = clone ? true : false;
previsibleMethod()(cloneNote, sourceNoteName);
});
element.on('shown.bs.modal', function(e) {
if (scope.targetinput) {
angular.element(e.target).find('input#' + scope.targetinput).select();
}
postVisibleMethod();
});
}
};
}
})();

View file

@ -29,6 +29,9 @@ limitations under the License.
<input placeholder="Note name" type="text" class="form-control" id="noteImportName"
ng-model="note.noteImportName" />
</div>
<div class="form-group">
<label for="fileSizeLimit">JSON file size cannot exceed {{maxLimit}} MB</label>
</div>
<div class="form-group" ng-show="note.errorText">
<div class="alert alert-danger">{{note.errorText}}</div>

View file

@ -1,113 +1,133 @@
/*
* 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.
*/
* 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';
(function() {
angular.module('zeppelinWebApp').controller('NoteImportCtrl', function($scope, $timeout, websocketMsgSrv) {
var vm = this;
$scope.note = {};
$scope.note.step1 = true;
$scope.note.step2 = false;
angular.module('zeppelinWebApp').controller('NoteImportCtrl', NoteImportCtrl);
vm.resetFlags = function() {
NoteImportCtrl.$inject = ['$scope', '$timeout', 'websocketMsgSrv'];
function NoteImportCtrl($scope, $timeout, websocketMsgSrv) {
var vm = this;
$scope.note = {};
$scope.note.step1 = true;
$scope.note.step2 = false;
angular.element('#noteImportFile').val('');
};
$scope.maxLimit = '';
var limit = 0;
$scope.uploadFile = function() {
angular.element('#noteImportFile').click();
};
websocketMsgSrv.listConfigurations();
$scope.$on('configurationsInfo', function(scope, event) {
limit = event.configurations['zeppelin.websocket.max.text.message.size'];
$scope.maxLimit = Math.round(limit / 1048576);
});
$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);
vm.resetFlags = function() {
$scope.note = {};
$scope.note.step1 = true;
$scope.note.step2 = false;
angular.element('#noteImportFile').val('');
};
if (file) {
reader.readAsText(file);
}
};
$scope.uploadFile = function() {
angular.element('#noteImportFile').click();
};
$scope.uploadURL = function() {
$scope.note.errorText = '';
$scope.note.step1 = false;
$timeout(function() {
$scope.note.step2 = true;
}, 400);
};
$scope.importFile = function(element) {
$scope.note.errorText = '';
$scope.note.importFile = element.files[0];
var file = $scope.note.importFile;
var reader = new FileReader();
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';
if (file.size > limit) {
$scope.note.errorText = 'File size limit Exceeded!';
$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;
reader.onloadend = function() {
vm.processImportJson(reader.result);
};
if (file) {
reader.readAsText(file);
}
websocketMsgSrv.importNotebook(result);
//angular.element('#noteImportModal').modal('hide');
} else {
$scope.note.errorText = 'Invalid JSON';
}
$scope.$apply();
};
};
/*
** $scope.$on functions below
*/
$scope.uploadURL = function() {
$scope.note.errorText = '';
$scope.note.step1 = false;
$timeout(function() {
$scope.note.step2 = true;
}, 400);
};
$scope.$on('setNoteMenu', function(event, notes) {
vm.resetFlags();
angular.element('#noteImportModal').modal('hide');
});
});
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 functions below
*/
$scope.$on('setNoteMenu', function(event, notes) {
vm.resetFlags();
angular.element('#noteImportModal').modal('hide');
});
}
})();

View file

@ -12,54 +12,58 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').factory('notebookListDataFactory', function() {
angular.module('zeppelinWebApp').factory('notebookListDataFactory', notebookListDataFactory);
var notes = {
root: {children: []},
flatList: [],
function notebookListDataFactory() {
var notes = {
root: {children: []},
flatList: [],
setNotes: function(notesList) {
// a flat list to boost searching
notes.flatList = angular.copy(notesList);
setNotes: function(notesList) {
// a flat list to boost searching
notes.flatList = angular.copy(notesList);
// construct the folder-based tree
notes.root = {children: []};
_.reduce(notesList, function(root, note) {
var noteName = note.name || note.id;
var nodes = noteName.match(/([^\/][^\/]*)/g);
// construct the folder-based tree
notes.root = {children: []};
_.reduce(notesList, function(root, note) {
var noteName = note.name || note.id;
var nodes = noteName.match(/([^\/][^\/]*)/g);
// recursively add nodes
addNode(root, nodes, note.id);
// recursively add nodes
addNode(root, nodes, note.id);
return root;
}, notes.root);
}
};
var addNode = function(curDir, nodes, noteId) {
if (nodes.length === 1) { // the leaf
curDir.children.push({
name: nodes[0],
id: noteId
});
} else { // a folder node
var node = nodes.shift();
var dir = _.find(curDir.children,
function(c) {return c.name === node && c.children !== undefined;});
if (dir !== undefined) { // found an existing dir
addNode(dir, nodes, noteId);
} else {
var newDir = {
name: node,
hidden: true,
children: []
};
curDir.children.push(newDir);
addNode(newDir, nodes, noteId);
return root;
}, notes.root);
}
}
};
};
return notes;
});
var addNode = function(curDir, nodes, noteId) {
if (nodes.length === 1) { // the leaf
curDir.children.push({
name: nodes[0],
id: noteId
});
} else { // a folder node
var node = nodes.shift();
var dir = _.find(curDir.children,
function(c) {return c.name === node && c.children !== undefined;});
if (dir !== undefined) { // found an existing dir
addNode(dir, nodes, noteId);
} else {
var newDir = {
name: node,
hidden: true,
children: []
};
curDir.children.push(newDir);
addNode(newDir, nodes, noteId);
}
}
};
return notes;
}
})();

View file

@ -0,0 +1,28 @@
/*
* 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';
(function() {
angular.module('zeppelinWebApp').directive('popoverHtmlUnsafePopup', popoverHtmlUnsafePopup);
function popoverHtmlUnsafePopup() {
return {
restrict: 'EA',
replace: true,
scope: {title: '@', content: '@', placement: '@', animation: '&', isOpen: '&'},
templateUrl: 'components/popover-html-unsafe/popover-html-unsafe-popup.html'
};
}
})();

View file

@ -12,17 +12,14 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp')
.directive('popoverHtmlUnsafePopup', function() {
return {
restrict: 'EA',
replace: true,
scope: {title: '@', content: '@', placement: '@', animation: '&', isOpen: '&'},
templateUrl: 'components/popover-html-unsafe/popover-html-unsafe-popup.html'
};
})
angular.module('zeppelinWebApp').directive('popoverHtmlUnsafe', popoverHtmlUnsafe);
.directive('popoverHtmlUnsafe', ['$tooltip', function($tooltip) {
popoverHtmlUnsafe.$inject = ['$tooltip'];
function popoverHtmlUnsafe($tooltip) {
return $tooltip('popoverHtmlUnsafe', 'popover', 'click');
}]);
}
})();

View file

@ -62,6 +62,44 @@ limitations under the License.
<input type="password" class="form-control" id="repoPassword" ng-model="newRepoSetting.password" />
</div>
</div>
<hr/>
<div class="center-block"><h4>Proxy Settings (optional)</h4></div>
<br/>
<div class="form-group">
<div class="col-sm-10">
<label class="control-label col-sm-2" for="proxyProtocol1">Protocol</label>
<label class="radio-inline">
<input type="radio" name="proxyProtocol" id="proxyProtocol1" value="HTTP" ng-model="newRepoSetting.proxyProtocol"/> HTTP
</label>
<label class="radio-inline">
<input type="radio" name="proxyProtocol" id="proxyProtocol2" value="HTTPS" ng-model="newRepoSetting.proxyProtocol"/> HTTPS
</label>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="proxyHost">Host</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="proxyHost" ng-model="newRepoSetting.proxyHost" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="proxyPort">Port</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="proxyPort" ng-model="newRepoSetting.proxyPort" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="proxyLogin">Login</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="proxyLogin" ng-model="newRepoSetting.proxyLogin" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="proxyPassword">Password</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="proxyPassword" ng-model="newRepoSetting.proxyPassword" />
</div>
</div>
</div>
<div class="modal-footer">
<button type="submit"

View file

@ -12,58 +12,62 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').directive('resizable', function() {
angular.module('zeppelinWebApp').directive('resizable', resizable);
var resizableConfig = {
autoHide: true,
handles: 'se',
helper: 'resizable-helper',
stop: function() {
angular.element(this).css({'width': '100%', 'height': '100%'});
}
};
function resizable() {
var resizableConfig = {
autoHide: true,
handles: 'se',
helper: 'resizable-helper',
stop: function() {
angular.element(this).css({'width': '100%', 'height': '100%'});
}
};
return {
restrict: 'A',
scope: {
callback: '&onResize'
},
link: function postLink(scope, elem, attrs) {
attrs.$observe('resize', function(resize) {
var resetResize = function(elem, resize) {
var colStep = window.innerWidth / 12;
elem.off('resizestop');
var conf = angular.copy(resizableConfig);
if (resize.graphType === 'TABLE' || resize.graphType === 'TEXT') {
conf.grid = [colStep, 10];
conf.minHeight = 100;
} else {
conf.grid = [colStep, 10000];
conf.minHeight = 0;
}
conf.maxWidth = window.innerWidth;
elem.resizable(conf);
elem.on('resizestop', function() {
if (scope.callback) {
var height = elem.height();
if (height < 50) {
height = 300;
}
scope.callback({width: Math.ceil(elem.width() / colStep), height: height});
return {
restrict: 'A',
scope: {
callback: '&onResize'
},
link: function postLink(scope, elem, attrs) {
attrs.$observe('resize', function(resize) {
var resetResize = function(elem, resize) {
var colStep = window.innerWidth / 12;
elem.off('resizestop');
var conf = angular.copy(resizableConfig);
if (resize.graphType === 'TABLE' || resize.graphType === 'TEXT') {
conf.grid = [colStep, 10];
conf.minHeight = 100;
} else {
conf.grid = [colStep, 10000];
conf.minHeight = 0;
}
});
};
conf.maxWidth = window.innerWidth;
resize = JSON.parse(resize);
if (resize.allowresize === 'true') {
resetResize(elem, resize);
angular.element(window).resize(function() {
elem.resizable(conf);
elem.on('resizestop', function() {
if (scope.callback) {
var height = elem.height();
if (height < 50) {
height = 300;
}
scope.callback({width: Math.ceil(elem.width() / colStep), height: height});
}
});
};
resize = JSON.parse(resize);
if (resize.allowresize === 'true') {
resetResize(elem, resize);
});
}
});
}
};
});
angular.element(window).resize(function() {
resetResize(elem, resize);
});
}
});
}
};
}
})();

View file

@ -12,38 +12,44 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').service('saveAsService', function(browserDetectService) {
angular.module('zeppelinWebApp').service('saveAsService', saveAsService);
this.saveAs = function(content, filename, extension) {
var BOM = '\uFEFF';
if (browserDetectService.detectIE()) {
angular.element('body').append('<iframe id="SaveAsId" style="display: none"></iframe>');
var frameSaveAs = angular.element('body > iframe#SaveAsId')[0].contentWindow;
content = BOM + content;
frameSaveAs.document.open('text/json', 'replace');
frameSaveAs.document.write(content);
frameSaveAs.document.close();
frameSaveAs.focus();
var t1 = Date.now();
frameSaveAs.document.execCommand('SaveAs', false, filename + '.' + extension);
var t2 = Date.now();
saveAsService.$inject = ['browserDetectService'];
//This means, this version of IE dosen't support auto download of a file with extension provided in param
//falling back to ".txt"
if (t1 === t2) {
frameSaveAs.document.execCommand('SaveAs', true, filename + '.txt');
function saveAsService(browserDetectService) {
this.saveAs = function(content, filename, extension) {
var BOM = '\uFEFF';
if (browserDetectService.detectIE()) {
angular.element('body').append('<iframe id="SaveAsId" style="display: none"></iframe>');
var frameSaveAs = angular.element('body > iframe#SaveAsId')[0].contentWindow;
content = BOM + content;
frameSaveAs.document.open('text/json', 'replace');
frameSaveAs.document.write(content);
frameSaveAs.document.close();
frameSaveAs.focus();
var t1 = Date.now();
frameSaveAs.document.execCommand('SaveAs', false, filename + '.' + extension);
var t2 = Date.now();
//This means, this version of IE dosen't support auto download of a file with extension provided in param
//falling back to ".txt"
if (t1 === t2) {
frameSaveAs.document.execCommand('SaveAs', true, filename + '.txt');
}
angular.element('body > iframe#SaveAsId').remove();
} else {
content = 'data:image/svg;charset=utf-8,' + BOM + encodeURIComponent(content);
angular.element('body').append('<a id="SaveAsId"></a>');
var saveAsElement = angular.element('body > a#SaveAsId');
saveAsElement.attr('href', content);
saveAsElement.attr('download', filename + '.' + extension);
saveAsElement.attr('target', '_blank');
saveAsElement[0].click();
saveAsElement.remove();
}
angular.element('body > iframe#SaveAsId').remove();
} else {
content = 'data:image/svg;charset=utf-8,' + BOM + encodeURIComponent(content);
angular.element('body').append('<a id="SaveAsId"></a>');
var saveAsElement = angular.element('body > a#SaveAsId');
saveAsElement.attr('href', content);
saveAsElement.attr('download', filename + '.' + extension);
saveAsElement.attr('target', '_blank');
saveAsElement[0].click();
saveAsElement.remove();
}
};
});
};
}
})();

View file

@ -12,21 +12,26 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').service('searchService', function($resource, baseUrlSrv) {
angular.module('zeppelinWebApp').service('searchService', searchService);
this.search = function(term) {
this.searchTerm = term.q;
console.log('Searching for: %o', term.q);
if (!term.q) { //TODO(bzz): empty string check
return;
}
var encQuery = window.encodeURIComponent(term.q);
return $resource(baseUrlSrv.getRestApiBase() + '/notebook/search?q=' + encQuery, {}, {
query: {method: 'GET'}
});
};
searchService.$inject = ['$resource', 'baseUrlSrv'];
this.searchTerm = '';
function searchService($resource, baseUrlSrv) {
this.search = function(term) {
this.searchTerm = term.q;
console.log('Searching for: %o', term.q);
if (!term.q) { //TODO(bzz): empty string check
return;
}
var encQuery = window.encodeURIComponent(term.q);
return $resource(baseUrlSrv.getRestApiBase() + '/notebook/search?q=' + encQuery, {}, {
query: {method: 'GET'}
});
};
});
this.searchTerm = '';
}
})();

View file

@ -12,123 +12,146 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').factory('websocketEvents',
function($rootScope, $websocket, $location, baseUrlSrv) {
var websocketCalls = {};
angular.module('zeppelinWebApp').factory('websocketEvents', websocketEvents);
websocketCalls.ws = $websocket(baseUrlSrv.getWebsocketUrl());
websocketCalls.ws.reconnectIfNotNormalClose = true;
websocketEvents.$inject = ['$rootScope', '$websocket', '$location', 'baseUrlSrv'];
websocketCalls.ws.onOpen(function() {
console.log('Websocket created');
$rootScope.$broadcast('setConnectedStatus', true);
setInterval(function() {
websocketCalls.sendNewEvent({op: 'PING'});
}, 10000);
});
function websocketEvents($rootScope, $websocket, $location, baseUrlSrv) {
var websocketCalls = {};
websocketCalls.sendNewEvent = function(data) {
if ($rootScope.ticket !== undefined) {
data.principal = $rootScope.ticket.principal;
data.ticket = $rootScope.ticket.ticket;
data.roles = $rootScope.ticket.roles;
} else {
data.principal = '';
data.ticket = '';
data.roles = '';
}
console.log('Send >> %o, %o, %o, %o, %o', data.op, data.principal, data.ticket, data.roles, data);
websocketCalls.ws.send(JSON.stringify(data));
};
websocketCalls.ws = $websocket(baseUrlSrv.getWebsocketUrl());
websocketCalls.ws.reconnectIfNotNormalClose = true;
websocketCalls.isConnected = function() {
return (websocketCalls.ws.socket.readyState === 1);
};
websocketCalls.ws.onOpen(function() {
console.log('Websocket created');
$rootScope.$broadcast('setConnectedStatus', true);
setInterval(function() {
websocketCalls.sendNewEvent({op: 'PING'});
}, 10000);
});
websocketCalls.ws.onMessage(function(event) {
var payload;
if (event.data) {
payload = angular.fromJson(event.data);
}
console.log('Receive << %o, %o', payload.op, payload);
var op = payload.op;
var data = payload.data;
if (op === 'NOTE') {
$rootScope.$broadcast('setNoteContent', data.note);
} else if (op === 'NEW_NOTE') {
$location.path('/notebook/' + data.note.id);
} else if (op === 'NOTES_INFO') {
$rootScope.$broadcast('setNoteMenu', data.notes);
} else if (op === 'LIST_NOTEBOOK_JOBS') {
$rootScope.$broadcast('setNotebookJobs', data.notebookJobs);
} else if (op === 'LIST_UPDATE_NOTEBOOK_JOBS') {
$rootScope.$broadcast('setUpdateNotebookJobs', data.notebookRunningJobs);
} else if (op === 'AUTH_INFO') {
BootstrapDialog.show({
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
title: 'Insufficient privileges',
message: data.info.toString(),
buttons: [{
label: 'Login',
action: function(dialog) {
dialog.close();
angular.element('#loginModal').modal({
show: 'true'
});
}
}, {
label: 'Cancel',
action: function(dialog) {
dialog.close();
$location.path('/');
}
}]
});
} else if (op === 'PARAGRAPH') {
$rootScope.$broadcast('updateParagraph', data);
} else if (op === 'PARAGRAPH_APPEND_OUTPUT') {
$rootScope.$broadcast('appendParagraphOutput', data);
} else if (op === 'PARAGRAPH_UPDATE_OUTPUT') {
$rootScope.$broadcast('updateParagraphOutput', data);
} else if (op === 'PROGRESS') {
$rootScope.$broadcast('updateProgress', data);
} else if (op === 'COMPLETION_LIST') {
$rootScope.$broadcast('completionList', data);
} else if (op === 'EDITOR_SETTING') {
$rootScope.$broadcast('editorSetting', data);
} else if (op === 'ANGULAR_OBJECT_UPDATE') {
$rootScope.$broadcast('angularObjectUpdate', data);
} else if (op === 'ANGULAR_OBJECT_REMOVE') {
$rootScope.$broadcast('angularObjectRemove', data);
} else if (op === 'APP_APPEND_OUTPUT') {
$rootScope.$broadcast('appendAppOutput', data);
} else if (op === 'APP_UPDATE_OUTPUT') {
$rootScope.$broadcast('updateAppOutput', data);
} else if (op === 'APP_LOAD') {
$rootScope.$broadcast('appLoad', data);
} else if (op === 'APP_STATUS_CHANGE') {
$rootScope.$broadcast('appStatusChange', data);
} else if (op === 'LIST_REVISION_HISTORY') {
$rootScope.$broadcast('listRevisionHistory', data);
} else if (op === 'NOTE_REVISION') {
$rootScope.$broadcast('noteRevision', data);
} else if (op === 'INTERPRETER_BINDINGS') {
$rootScope.$broadcast('interpreterBindings', data);
}
});
websocketCalls.sendNewEvent = function(data) {
if ($rootScope.ticket !== undefined) {
data.principal = $rootScope.ticket.principal;
data.ticket = $rootScope.ticket.ticket;
data.roles = $rootScope.ticket.roles;
} else {
data.principal = '';
data.ticket = '';
data.roles = '';
}
console.log('Send >> %o, %o, %o, %o, %o', data.op, data.principal, data.ticket, data.roles, data);
websocketCalls.ws.send(JSON.stringify(data));
};
websocketCalls.ws.onError(function(event) {
console.log('error message: ', event);
$rootScope.$broadcast('setConnectedStatus', false);
});
websocketCalls.isConnected = function() {
return (websocketCalls.ws.socket.readyState === 1);
};
websocketCalls.ws.onClose(function(event) {
console.log('close message: ', event);
$rootScope.$broadcast('setConnectedStatus', false);
});
websocketCalls.ws.onMessage(function(event) {
var payload;
if (event.data) {
payload = angular.fromJson(event.data);
}
console.log('Receive << %o, %o', payload.op, payload);
var op = payload.op;
var data = payload.data;
if (op === 'NOTE') {
$rootScope.$broadcast('setNoteContent', data.note);
} else if (op === 'NEW_NOTE') {
$location.path('/notebook/' + data.note.id);
} else if (op === 'NOTES_INFO') {
$rootScope.$broadcast('setNoteMenu', data.notes);
} else if (op === 'LIST_NOTEBOOK_JOBS') {
$rootScope.$broadcast('setNotebookJobs', data.notebookJobs);
} else if (op === 'LIST_UPDATE_NOTEBOOK_JOBS') {
$rootScope.$broadcast('setUpdateNotebookJobs', data.notebookRunningJobs);
} else if (op === 'AUTH_INFO') {
BootstrapDialog.show({
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
title: 'Insufficient privileges',
message: data.info.toString(),
buttons: [{
label: 'Login',
action: function(dialog) {
dialog.close();
angular.element('#loginModal').modal({
show: 'true'
});
}
}, {
label: 'Cancel',
action: function(dialog) {
dialog.close();
$location.path('/');
}
}]
});
} else if (op === 'PARAGRAPH') {
$rootScope.$broadcast('updateParagraph', data);
} else if (op === 'PARAGRAPH_APPEND_OUTPUT') {
$rootScope.$broadcast('appendParagraphOutput', data);
} else if (op === 'PARAGRAPH_UPDATE_OUTPUT') {
$rootScope.$broadcast('updateParagraphOutput', data);
} else if (op === 'PROGRESS') {
$rootScope.$broadcast('updateProgress', data);
} else if (op === 'COMPLETION_LIST') {
$rootScope.$broadcast('completionList', data);
} else if (op === 'EDITOR_SETTING') {
$rootScope.$broadcast('editorSetting', data);
} else if (op === 'ANGULAR_OBJECT_UPDATE') {
$rootScope.$broadcast('angularObjectUpdate', data);
} else if (op === 'ANGULAR_OBJECT_REMOVE') {
$rootScope.$broadcast('angularObjectRemove', data);
} else if (op === 'APP_APPEND_OUTPUT') {
$rootScope.$broadcast('appendAppOutput', data);
} else if (op === 'APP_UPDATE_OUTPUT') {
$rootScope.$broadcast('updateAppOutput', data);
} else if (op === 'APP_LOAD') {
$rootScope.$broadcast('appLoad', data);
} else if (op === 'APP_STATUS_CHANGE') {
$rootScope.$broadcast('appStatusChange', data);
} else if (op === 'LIST_REVISION_HISTORY') {
$rootScope.$broadcast('listRevisionHistory', data);
} else if (op === 'NOTE_REVISION') {
$rootScope.$broadcast('noteRevision', data);
} else if (op === 'INTERPRETER_BINDINGS') {
$rootScope.$broadcast('interpreterBindings', data);
} else if (op === 'ERROR_INFO') {
BootstrapDialog.show({
closable: false,
closeByBackdrop: false,
closeByKeyboard: false,
title: 'Details',
message: data.info.toString(),
buttons: [{
// close all the dialogs when there are error on running all paragraphs
label: 'Close',
action: function() {
BootstrapDialog.closeAll();
}
}]
});
} else if (op === 'CONFIGURATIONS_INFO') {
$rootScope.$broadcast('configurationsInfo', data);
}
});
return websocketCalls;
});
websocketCalls.ws.onError(function(event) {
console.log('error message: ', event);
$rootScope.$broadcast('setConnectedStatus', false);
});
websocketCalls.ws.onClose(function(event) {
console.log('close message: ', event);
$rootScope.$broadcast('setConnectedStatus', false);
});
return websocketCalls;
}
})();

View file

@ -12,210 +12,220 @@
* limitations under the License.
*/
'use strict';
(function() {
angular.module('zeppelinWebApp').service('websocketMsgSrv', function($rootScope, websocketEvents) {
angular.module('zeppelinWebApp').service('websocketMsgSrv', websocketMsgSrv);
return {
websocketMsgSrv.$inject = ['$rootScope', 'websocketEvents'];
getHomeNotebook: function() {
websocketEvents.sendNewEvent({op: 'GET_HOME_NOTE'});
},
function websocketMsgSrv($rootScope, websocketEvents) {
return {
createNotebook: function(noteName) {
websocketEvents.sendNewEvent({op: 'NEW_NOTE',data: {name: noteName}});
},
getHomeNotebook: function() {
websocketEvents.sendNewEvent({op: 'GET_HOME_NOTE'});
},
deleteNotebook: function(noteId) {
websocketEvents.sendNewEvent({op: 'DEL_NOTE', data: {id: noteId}});
},
createNotebook: function(noteName) {
websocketEvents.sendNewEvent({op: 'NEW_NOTE',data: {name: noteName}});
},
cloneNotebook: function(noteIdToClone, newNoteName) {
websocketEvents.sendNewEvent({op: 'CLONE_NOTE', data: {id: noteIdToClone, name: newNoteName}});
},
deleteNotebook: function(noteId) {
websocketEvents.sendNewEvent({op: 'DEL_NOTE', data: {id: noteId}});
},
getNotebookList: function() {
websocketEvents.sendNewEvent({op: 'LIST_NOTES'});
},
cloneNotebook: function(noteIdToClone, newNoteName) {
websocketEvents.sendNewEvent({op: 'CLONE_NOTE', data: {id: noteIdToClone, name: newNoteName}});
},
reloadAllNotesFromRepo: function() {
websocketEvents.sendNewEvent({op: 'RELOAD_NOTES_FROM_REPO'});
},
getNotebookList: function() {
websocketEvents.sendNewEvent({op: 'LIST_NOTES'});
},
getNotebook: function(noteId) {
websocketEvents.sendNewEvent({op: 'GET_NOTE', data: {id: noteId}});
},
reloadAllNotesFromRepo: function() {
websocketEvents.sendNewEvent({op: 'RELOAD_NOTES_FROM_REPO'});
},
updateNotebook: function(noteId, noteName, noteConfig) {
websocketEvents.sendNewEvent({op: 'NOTE_UPDATE', data: {id: noteId, name: noteName, config: noteConfig}});
},
getNotebook: function(noteId) {
websocketEvents.sendNewEvent({op: 'GET_NOTE', data: {id: noteId}});
},
moveParagraph: function(paragraphId, newIndex) {
websocketEvents.sendNewEvent({op: 'MOVE_PARAGRAPH', data: {id: paragraphId, index: newIndex}});
},
updateNotebook: function(noteId, noteName, noteConfig) {
websocketEvents.sendNewEvent({op: 'NOTE_UPDATE', data: {id: noteId, name: noteName, config: noteConfig}});
},
insertParagraph: function(newIndex) {
websocketEvents.sendNewEvent({op: 'INSERT_PARAGRAPH', data: {index: newIndex}});
},
moveParagraph: function(paragraphId, newIndex) {
websocketEvents.sendNewEvent({op: 'MOVE_PARAGRAPH', data: {id: paragraphId, index: newIndex}});
},
updateAngularObject: function(noteId, paragraphId, name, value, interpreterGroupId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_UPDATED',
data: {
noteId: noteId,
paragraphId: paragraphId,
name: name,
value: value,
interpreterGroupId: interpreterGroupId
}
});
},
insertParagraph: function(newIndex) {
websocketEvents.sendNewEvent({op: 'INSERT_PARAGRAPH', data: {index: newIndex}});
},
clientBindAngularObject: function(noteId, name, value, paragraphId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_CLIENT_BIND',
data: {
noteId: noteId,
name: name,
value: value,
paragraphId: paragraphId
}
});
},
updateAngularObject: function(noteId, paragraphId, name, value, interpreterGroupId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_UPDATED',
data: {
noteId: noteId,
paragraphId: paragraphId,
name: name,
value: value,
interpreterGroupId: interpreterGroupId
}
});
},
clientUnbindAngularObject: function(noteId, name, paragraphId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_CLIENT_UNBIND',
data: {
noteId: noteId,
name: name,
paragraphId: paragraphId
}
});
},
clientBindAngularObject: function(noteId, name, value, paragraphId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_CLIENT_BIND',
data: {
noteId: noteId,
name: name,
value: value,
paragraphId: paragraphId
}
});
},
cancelParagraphRun: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'CANCEL_PARAGRAPH', data: {id: paragraphId}});
},
clientUnbindAngularObject: function(noteId, name, paragraphId) {
websocketEvents.sendNewEvent({
op: 'ANGULAR_OBJECT_CLIENT_UNBIND',
data: {
noteId: noteId,
name: name,
paragraphId: paragraphId
}
});
},
runParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
websocketEvents.sendNewEvent({
op: 'RUN_PARAGRAPH',
data: {
id: paragraphId,
title: paragraphTitle,
paragraph: paragraphData,
config: paragraphConfig,
params: paragraphParams
}
});
},
cancelParagraphRun: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'CANCEL_PARAGRAPH', data: {id: paragraphId}});
},
removeParagraph: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'PARAGRAPH_REMOVE', data: {id: paragraphId}});
},
runParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
websocketEvents.sendNewEvent({
op: 'RUN_PARAGRAPH',
data: {
id: paragraphId,
title: paragraphTitle,
paragraph: paragraphData,
config: paragraphConfig,
params: paragraphParams
}
});
},
clearParagraphOutput: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_OUTPUT', data: {id: paragraphId}});
},
removeParagraph: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'PARAGRAPH_REMOVE', data: {id: paragraphId}});
},
completion: function(paragraphId, buf, cursor) {
websocketEvents.sendNewEvent({
op: 'COMPLETION',
data: {
id: paragraphId,
buf: buf,
cursor: cursor
}
});
},
clearParagraphOutput: function(paragraphId) {
websocketEvents.sendNewEvent({op: 'PARAGRAPH_CLEAR_OUTPUT', data: {id: paragraphId}});
},
commitParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
websocketEvents.sendNewEvent({
op: 'COMMIT_PARAGRAPH',
data: {
id: paragraphId,
title: paragraphTitle,
paragraph: paragraphData,
config: paragraphConfig,
params: paragraphParams
}
});
},
completion: function(paragraphId, buf, cursor) {
websocketEvents.sendNewEvent({
op: 'COMPLETION',
data: {
id: paragraphId,
buf: buf,
cursor: cursor
}
});
},
importNotebook: function(notebook) {
websocketEvents.sendNewEvent({
op: 'IMPORT_NOTE',
data: {
notebook: notebook
}
});
},
commitParagraph: function(paragraphId, paragraphTitle, paragraphData, paragraphConfig, paragraphParams) {
websocketEvents.sendNewEvent({
op: 'COMMIT_PARAGRAPH',
data: {
id: paragraphId,
title: paragraphTitle,
paragraph: paragraphData,
config: paragraphConfig,
params: paragraphParams
}
});
},
checkpointNotebook: function(noteId, commitMessage) {
websocketEvents.sendNewEvent({
op: 'CHECKPOINT_NOTEBOOK',
data: {
noteId: noteId,
commitMessage: commitMessage
}
});
},
importNotebook: function(notebook) {
websocketEvents.sendNewEvent({
op: 'IMPORT_NOTE',
data: {
notebook: notebook
}
});
},
listRevisionHistory: function(noteId) {
websocketEvents.sendNewEvent({
op: 'LIST_REVISION_HISTORY',
data: {
noteId: noteId
}
});
},
checkpointNotebook: function(noteId, commitMessage) {
websocketEvents.sendNewEvent({
op: 'CHECKPOINT_NOTEBOOK',
data: {
noteId: noteId,
commitMessage: commitMessage
}
});
},
getNoteByRevision: function(noteId, revisionId) {
websocketEvents.sendNewEvent({
op: 'NOTE_REVISION',
data: {
noteId: noteId,
revisionId: revisionId
}
});
},
listRevisionHistory: function(noteId) {
websocketEvents.sendNewEvent({
op: 'LIST_REVISION_HISTORY',
data: {
noteId: noteId
}
});
},
getEditorSetting: function(replName) {
websocketEvents.sendNewEvent({
op: 'EDITOR_SETTING',
data: {
magic: replName
}
});
},
getNoteByRevision: function(noteId, revisionId) {
websocketEvents.sendNewEvent({
op: 'NOTE_REVISION',
data: {
noteId: noteId,
revisionId: revisionId
}
});
},
isConnected: function() {
return websocketEvents.isConnected();
},
getEditorSetting: function(paragraphId, replName) {
websocketEvents.sendNewEvent({
op: 'EDITOR_SETTING',
data: {
paragraphId: paragraphId,
magic: replName
}
});
},
getNotebookJobsList: function() {
websocketEvents.sendNewEvent({op: 'LIST_NOTEBOOK_JOBS'});
},
isConnected: function() {
return websocketEvents.isConnected();
},
getUpdateNotebookJobsList: function(lastUpdateServerUnixTime) {
websocketEvents.sendNewEvent(
{op: 'LIST_UPDATE_NOTEBOOK_JOBS', data: {lastUpdateUnixTime: lastUpdateServerUnixTime * 1}}
);
},
getNotebookJobsList: function() {
websocketEvents.sendNewEvent({op: 'LIST_NOTEBOOK_JOBS'});
},
unsubscribeJobManager: function() {
websocketEvents.sendNewEvent({op: 'UNSUBSCRIBE_UPDATE_NOTEBOOK_JOBS'});
},
getUpdateNotebookJobsList: function(lastUpdateServerUnixTime) {
websocketEvents.sendNewEvent(
{op: 'LIST_UPDATE_NOTEBOOK_JOBS', data: {lastUpdateUnixTime: lastUpdateServerUnixTime * 1}}
);
},
getInterpreterBindings: function(noteID) {
websocketEvents.sendNewEvent({op: 'GET_INTERPRETER_BINDINGS', data: {noteID: noteID}});
},
unsubscribeJobManager: function() {
websocketEvents.sendNewEvent({op: 'UNSUBSCRIBE_UPDATE_NOTEBOOK_JOBS'});
},
saveInterpreterBindings: function(noteID, selectedSettingIds) {
websocketEvents.sendNewEvent({op: 'SAVE_INTERPRETER_BINDINGS',
data: {noteID: noteID, selectedSettingIds: selectedSettingIds}});
}
getInterpreterBindings: function(noteID) {
websocketEvents.sendNewEvent({op: 'GET_INTERPRETER_BINDINGS', data: {noteID: noteID}});
},
};
saveInterpreterBindings: function(noteID, selectedSettingIds) {
websocketEvents.sendNewEvent({op: 'SAVE_INTERPRETER_BINDINGS',
data: {noteID: noteID, selectedSettingIds: selectedSettingIds}});
},
});
listConfigurations: function() {
websocketEvents.sendNewEvent({op: 'LIST_CONFIGURATIONS'});
}
};
}
})();

View file

@ -171,6 +171,7 @@ limitations under the License.
<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/popover-html-unsafe/popover-html-unsafe-popup.directive.js"></script>
<script src="components/ngenter/ngenter.directive.js"></script>
<script src="components/dropdowninput/dropdowninput.directive.js"></script>
<script src="components/resizable/resizable.directive.js"></script>

View file

@ -0,0 +1,42 @@
'use strict';
describe('Controller: NotenameCtrl', function() {
beforeEach(module('zeppelinWebApp'));
var scope;
var ctrl;
var notebookList;
beforeEach(inject(function($injector, $rootScope, $controller) {
notebookList = $injector.get('notebookListDataFactory');
scope = $rootScope.$new();
ctrl = $controller('NotenameCtrl', {
$scope: scope,
notebookListDataFactory: notebookList
});
}));
it('should create a new name from current name when cloneNoteName is called', function() {
var notesList = [
{name: 'dsds 1', id: '1'},
{name: 'dsds 2', id: '2'},
{name: 'test name', id: '3'},
{name: 'aa bb cc', id: '4'},
{name: 'Untitled Note 6', id: '4'}
];
notebookList.setNotes(notesList);
ctrl.sourceNoteName = 'test name';
expect(ctrl.cloneNoteName()).toEqual('test name 1');
ctrl.sourceNoteName = 'aa bb cc';
expect(ctrl.cloneNoteName()).toEqual('aa bb cc 1');
ctrl.sourceNoteName = 'Untitled Note 6';
expect(ctrl.cloneNoteName()).toEqual('Untitled Note 7');
ctrl.sourceNoteName = 'My_note';
expect(ctrl.cloneNoteName()).toEqual('My_note 1');
ctrl.sourceNoteName = 'dsds 2';
expect(ctrl.cloneNoteName()).toEqual('dsds 3');
});
});

View file

@ -261,6 +261,10 @@ public class ZeppelinConfiguration extends XMLConfiguration {
return getBoolean(ConfVars.ZEPPELIN_SSL);
}
public int getServerSslPort() {
return getInt(ConfVars.ZEPPELIN_SSL_PORT);
}
public boolean useClientAuth() {
return getBoolean(ConfVars.ZEPPELIN_SSL_CLIENT_AUTH);
}
@ -489,6 +493,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
ZEPPELIN_PORT("zeppelin.server.port", 8080),
ZEPPELIN_SERVER_CONTEXT_PATH("zeppelin.server.context.path", "/"),
ZEPPELIN_SSL("zeppelin.ssl", false),
ZEPPELIN_SSL_PORT("zeppelin.server.ssl.port", 8443),
ZEPPELIN_SSL_CLIENT_AUTH("zeppelin.ssl.client.auth", false),
ZEPPELIN_SSL_KEYSTORE_PATH("zeppelin.ssl.keystore.path", "keystore"),
ZEPPELIN_SSL_KEYSTORE_TYPE("zeppelin.ssl.keystore.type", "JKS"),
@ -529,7 +534,8 @@ public class ZeppelinConfiguration extends XMLConfiguration {
+ "org.apache.zeppelin.scalding.ScaldingInterpreter,"
+ "org.apache.zeppelin.jdbc.JDBCInterpreter,"
+ "org.apache.zeppelin.hbase.HbaseInterpreter,"
+ "org.apache.zeppelin.bigquery.BigQueryInterpreter"),
+ "org.apache.zeppelin.bigquery.BigQueryInterpreter,"
+ "org.apache.zeppelin.beam.BeamInterpreter"),
ZEPPELIN_INTERPRETER_JSON("zeppelin.interpreter.setting", "interpreter-setting.json"),
ZEPPELIN_INTERPRETER_DIR("zeppelin.interpreter.dir", "interpreter"),
ZEPPELIN_INTERPRETER_LOCALREPO("zeppelin.interpreter.localRepo", "local-repo"),
@ -537,7 +543,7 @@ public class ZeppelinConfiguration extends XMLConfiguration {
ZEPPELIN_INTERPRETER_MAX_POOL_SIZE("zeppelin.interpreter.max.poolsize", 10),
ZEPPELIN_INTERPRETER_GROUP_ORDER("zeppelin.interpreter.group.order", "spark,md,angular,sh,"
+ "livy,alluxio,file,psql,flink,python,ignite,lens,cassandra,geode,kylin,elasticsearch,"
+ "scalding,jdbc,hbase,bigquery"),
+ "scalding,jdbc,hbase,bigquery,beam"),
ZEPPELIN_ENCODING("zeppelin.encoding", "UTF-8"),
ZEPPELIN_NOTEBOOK_DIR("zeppelin.notebook.dir", "notebook"),
// use specified notebook (id) as homescreen

View file

@ -62,6 +62,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.aether.RepositoryException;
import org.sonatype.aether.repository.Authentication;
import org.sonatype.aether.repository.Proxy;
import org.sonatype.aether.repository.RemoteRepository;
import org.apache.zeppelin.conf.ZeppelinConfiguration;
@ -432,6 +433,7 @@ public class InterpreterFactory implements InterpreterGroupFactory {
private void loadInterpreterDependencies(final InterpreterSetting setting) {
setting.setStatus(InterpreterSetting.Status.DOWNLOADING_DEPENDENCIES);
setting.setErrorReason(null);
interpreterSettings.put(setting.getId(), setting);
synchronized (interpreterSettings) {
final Thread t = new Thread() {
@ -460,11 +462,12 @@ public class InterpreterFactory implements InterpreterGroupFactory {
}
setting.setStatus(InterpreterSetting.Status.READY);
setting.setErrorReason(null);
} catch (Exception e) {
logger.error(String.format("Error while downloading repos for interpreter group : %s," +
" go to interpreter setting page click on edit and save it again to make " +
"this interpreter work properly.",
setting.getGroup()), e);
"this interpreter work properly. : %s",
setting.getGroup(), e.getLocalizedMessage()), e);
setting.setErrorReason(e.getLocalizedMessage());
setting.setStatus(InterpreterSetting.Status.ERROR);
} finally {
@ -1326,9 +1329,9 @@ public class InterpreterFactory implements InterpreterGroupFactory {
return this.interpreterRepositories;
}
public void addRepository(String id, String url, boolean snapshot, Authentication auth)
throws IOException {
depResolver.addRepo(id, url, snapshot, auth);
public void addRepository(String id, String url, boolean snapshot, Authentication auth,
Proxy proxy) throws IOException {
depResolver.addRepo(id, url, snapshot, auth, proxy);
saveToFile();
}

Some files were not shown because too many files have changed in this diff Show more