Merge remote-tracking branch 'origin/master' into livyInterperter

This commit is contained in:
Prabhjyot Singh 2016-05-19 12:15:44 +05:30
commit 5c2bf139ae
10 changed files with 86 additions and 35 deletions

View file

@ -18,10 +18,11 @@ Core feature:
To know more about Zeppelin, visit our web site [http://zeppelin.incubator.apache.org](http://zeppelin.incubator.apache.org)
## Requirements
* Git
* Java 1.7
* Tested on Mac OSX, Ubuntu 14.X, CentOS 6.X
* Tested on Mac OSX, Ubuntu 14.X, CentOS 6.X, Windows 7 Pro SP1
* Maven (if you want to build from the source code)
* Node.js Package Manager (npm)
* Node.js Package Manager (npm, downloaded by Maven during build phase)
## Getting Started
@ -29,14 +30,49 @@ To know more about Zeppelin, visit our web site [http://zeppelin.incubator.apach
If you don't have requirements prepared, install it.
(The installation method may vary according to your environment, example is for Ubuntu.)
```sh
```
sudo apt-get update
sudo apt-get install git
sudo apt-get install openjdk-7-jdk
sudo apt-get install npm
sudo apt-get install libfontconfig
```
# install maven
#### Proxy settings (optional)
If you are behind a corporate Proxy with NTLM authentication you can use [Cntlm Authentication Proxy](http://cntlm.sourceforge.net/) .
Before build start, run these commands from shell.
```
export http_proxy=http://localhost:3128
export https_proxy=http://localhost:3128
export HTTP_PROXY=http://localhost:3128
export HTTPS_PROXY=http://localhost:3128
npm config set proxy http://localhost:3128
npm config set https-proxy http://localhost:3128
npm config set registry "http://registry.npmjs.org/"
npm config set strict-ssl false
npm cache clean
git config --global http.proxy http://localhost:3128
git config --global https.proxy http://localhost:3128
git config --global url."http://".insteadOf git://
```
After build is complete, run these commands to cleanup.
```
npm config rm proxy
npm config rm https-proxy
git config --global --unset http.proxy
git config --global --unset https.proxy
git config --global --unset url."http://".insteadOf
```
_Notes:_
- If you are on Windows replace `export` with `set` to set env variables
- Replace `localhost:3128` with standard pattern `http://user:pwd@host:port`
- Git configuration is needed because Bower use it for fetching from GitHub
#### Install maven
```
wget http://www.eu.apache.org/dist/maven/maven-3/3.3.3/binaries/apache-maven-3.3.3-bin.tar.gz
sudo tar -zxf apache-maven-3.3.3-bin.tar.gz -C /usr/local/
sudo ln -s /usr/local/apache-maven-3.3.3/bin/mvn /usr/local/bin/mvn

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 KiB

View file

@ -34,11 +34,12 @@ This instruction based on Ubuntu 14.04 LTS but may work with other OS with few c
1. Install NGINX server on your server instance
You can install NGINX server with same machine where zeppelin installed or separate machine where it is dedicated to serve as proxy server.
You can install NGINX server with same box where zeppelin installed or separate box where it is dedicated to serve as proxy server.
```
$ apt-get install nginx
```
*Important: On pre 1.3.13 version of NGINX, Proxy for Websocket may not fully works. Please use latest version of NGINX. See: [NGINX documentation](https://www.nginx.com/blog/websocket-nginx/)*
1. Setup init script in NGINX
@ -46,30 +47,30 @@ This instruction based on Ubuntu 14.04 LTS but may work with other OS with few c
```
$ cd /etc/nginx/sites-available
$ touch my-basic-auth
$ touch my-zeppelin-auth-setting
```
Now add this script into `my-basic-auth` file. You can comment out `optional` lines If you want serve Zeppelin under regular HTTP 80 Port.
Now add this script into `my-zeppelin-auth-setting` file. You can comment out `optional` lines If you want serve Zeppelin under regular HTTP 80 Port.
```
upstream zeppelin {
server [YOUR-ZEPPELIN-SERVER-IP]:8080;
server [YOUR-ZEPPELIN-SERVER-IP]:[YOUR-ZEPPELIN-SERVER-PORT]; # For security, It is highly recommended to make this address/port as non-public accessible
}
# Zeppelin Website
server {
listen [YOUR-ZEPPELIN-WEB-SERVER-PORT];
listen 443 ssl; # optional, to serve HTTPS connection
server_name [YOUR-ZEPPELIN-SERVER-HOST]; # for example: zeppelin.mycompany.com
listen 443 ssl; # optional, to serve HTTPS connection
server_name [YOUR-ZEPPELIN-SERVER-HOST]; # for example: zeppelin.mycompany.com
ssl_certificate [PATH-TO-YOUR-CERT-FILE]; # optional, to serve HTTPS connection
ssl_certificate_key [PATH-TO-YOUR-CERT-KEY-FILE]; # optional, to serve HTTPS connection
if ($ssl_protocol = "") {
rewrite ^ https://$host$request_uri? permanent; # optional, force to use HTTPS
rewrite ^ https://$host$request_uri? permanent; # optional, to force use of HTTPS
}
location / {
location / { # For regular websever support
proxy_pass http://zeppelin;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
@ -80,7 +81,7 @@ This instruction based on Ubuntu 14.04 LTS but may work with other OS with few c
auth_basic_user_file /etc/nginx/.htpasswd;
}
location /ws {
location /ws { # For websocket support
proxy_pass http://zeppelin;
proxy_http_version 1.1;
proxy_set_header Upgrade websocket;
@ -93,7 +94,7 @@ This instruction based on Ubuntu 14.04 LTS but may work with other OS with few c
Then make a symbolic link to this file from `/etc/nginx/sites-enabled/` to enable configuration above when NGINX reloads.
```
$ ln -s /etc/nginx/sites-enabled/my-basic-auth /etc/nginx/sites-available/my-basic-auth
$ ln -s /etc/nginx/sites-enabled/my-zeppelin-auth-setting /etc/nginx/sites-available/my-zeppelin-auth-setting
```
1. Setup user credential into `.htpasswd` file and restart server
@ -102,11 +103,11 @@ This instruction based on Ubuntu 14.04 LTS but may work with other OS with few c
```
$ cd /etc/nginx
$ htpasswd -c htpasswd [YOUR_ID]
$ NEW passwd: [YOUR_PASSWORD]
$ RE-type new passwd: [YOUR_PASSWORD_AGAIN]
$ htpasswd -c htpasswd [YOUR-ID]
$ NEW passwd: [YOUR-PASSWORD]
$ RE-type new passwd: [YOUR-PASSWORD-AGAIN]
```
Or you can use your own apache `.htpasswd` files in other location by setup property `auth_basic_user_file`
Or you can use your own apache `.htpasswd` files in other location for setting up property: `auth_basic_user_file`
Restart NGINX server.
@ -115,9 +116,6 @@ This instruction based on Ubuntu 14.04 LTS but may work with other OS with few c
```
Then check HTTP Basic Authentication works in browser. If you can see regular basic auth popup and then able to login with credential you entered into `.htpasswd` you are good to go.
<img src="/assets/themes/zeppelin/img/screenshots/authentication-basic-auth-nginx-request.png" />
<img src="/assets/themes/zeppelin/img/screenshots/authentication-basic-auth-nginx-https.png" />
1. More security consideration
* Using HTTPS connection with Basic Authentication is highly recommended since basic auth without encryption may expose your important credential information over the network.

View file

@ -22,8 +22,8 @@ import org.apache.commons.io.IOUtils;
import org.apache.zeppelin.interpreter.InterpreterException;
import org.apache.zeppelin.interpreter.InterpreterOutput;
import org.apache.zeppelin.interpreter.InterpreterOutputListener;
import parquet.org.slf4j.Logger;
import parquet.org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.Collections;

View file

@ -399,14 +399,17 @@ public class NotebookServer extends WebSocketServlet implements
broadcastAll(new Message(OP.NOTES_INFO).put("notes", notesInfo));
}
void permissionError(NotebookSocket conn, String op, Set<String> current,
Set<String> allowed) throws IOException {
void permissionError(NotebookSocket conn, String op, Set<String> userAndRoles,
Set<String> allowed) throws IOException {
LOG.info("Cannot {}. Connection readers {}. Allowed readers {}",
op, current, allowed);
op, userAndRoles, allowed);
String userName = userAndRoles.iterator().next();
conn.send(serializeMessage(new Message(OP.AUTH_INFO).put("info",
"Insufficient privileges to " + op + " note.\n\n" +
"Insufficient privileges to " + op + " notebook.\n\n" +
"Allowed users or roles: " + allowed.toString() + "\n\n" +
"User belongs to: " + current.toString())));
"But the user " + userName + " belongs to: " + userAndRoles.toString())));
}
private void sendNote(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook,
@ -1009,6 +1012,7 @@ public class NotebookServer extends WebSocketServlet implements
new InterpreterResult(InterpreterResult.Code.ERROR, ex.getMessage()),
ex);
p.setStatus(Status.ERROR);
broadcast(note.id(), new Message(OP.PARAGRAPH).put("paragraph", p));
}
}
}

View file

@ -364,7 +364,9 @@ angular.module('zeppelinWebApp')
var newType = $scope.getResultType(data.paragraph);
var oldGraphMode = $scope.getGraphMode();
var newGraphMode = $scope.getGraphMode(data.paragraph);
var resultRefreshed = (data.paragraph.dateFinished !== $scope.paragraph.dateFinished) || isEmpty(data.paragraph.result) !== isEmpty($scope.paragraph.result);
var resultRefreshed = (data.paragraph.dateFinished !== $scope.paragraph.dateFinished) ||
isEmpty(data.paragraph.result) !== isEmpty($scope.paragraph.result) ||
data.paragraph.status === 'ERROR';
var statusChanged = (data.paragraph.status !== $scope.paragraph.status);

View file

@ -354,6 +354,7 @@ table.dataTable.table-condensed .sorting_desc:after {
.tableDisplay .option .columns ul {
background: white;
overflow: auto;
width: auto;
padding: 3px 3px 3px 3px;
height: 150px;

View file

@ -27,7 +27,7 @@ angular.module('zeppelinWebApp').factory('notebookListDataFactory', function() {
notes.root = {children: []};
_.reduce(notesList, function(root, note) {
var noteName = note.name || note.id;
var nodes = noteName.match(/([^\\\][^\/]|\\\/)+/g);
var nodes = noteName.match(/([^\/][^\/]*)/g);
// recursively add nodes
addNode(root, nodes, note.id);

View file

@ -16,17 +16,18 @@ describe('Factory: NotebookList', function() {
var notesList = [
{name: 'A', id: '000001'},
{name: 'B', id: '000002'},
{id: '000003'}, // notebook without name
{id: '000003'}, // notebook without name
{name: '/C/CA', id: '000004'},
{name: '/C/CB', id: '000005'},
{name: '/C/CB/CBA', id: '000006'}, // same name with a dir
{name: '/C/CB/CBA', id: '000007'}, // same name with another note
{name: 'C///CB//CBB', id: '000008'}
{name: '/C/CB/CBA', id: '000007'}, // same name with another note
{name: 'C///CB//CBB', id: '000008'},
{name: 'D/D[A/DA]B', id:'000009'} // check if '[' and ']' considered as folder seperator
];
notebookList.setNotes(notesList);
var flatList = notebookList.flatList;
expect(flatList.length).toBe(8);
expect(flatList.length).toBe(9);
expect(flatList[0].name).toBe('A');
expect(flatList[0].id).toBe('000001');
expect(flatList[1].name).toBe('B');
@ -36,9 +37,10 @@ describe('Factory: NotebookList', function() {
expect(flatList[5].name).toBe('/C/CB/CBA');
expect(flatList[6].name).toBe('/C/CB/CBA');
expect(flatList[7].name).toBe('C///CB//CBB');
expect(flatList[8].name).toBe('D/D[A/DA]B');
var folderList = notebookList.root.children;
expect(folderList.length).toBe(4);
expect(folderList.length).toBe(5);
expect(folderList[0].name).toBe('A');
expect(folderList[0].id).toBe('000001');
expect(folderList[1].name).toBe('B');
@ -64,6 +66,14 @@ describe('Factory: NotebookList', function() {
expect(folderList[3].children[2].children[2].name).toBe('CBB');
expect(folderList[3].children[2].children[2].id).toBe('000008');
expect(folderList[3].children[2].children[2].children).toBeUndefined();
expect(folderList[4].name).toBe('D');
expect(folderList[4].id).toBeUndefined();
expect(folderList[4].children.length).toBe(1);
expect(folderList[4].children[0].name).toBe('D[A');
expect(folderList[4].children[0].id).toBeUndefined();
expect(folderList[4].children[0].children[0].name).toBe('DA]B');
expect(folderList[4].children[0].children[0].id).toBe('000009');
expect(folderList[4].children[0].children[0].children).toBeUndefined();
});
});