[ZEPPELIN-1210] Run interpreter per user ### What is this PR for? Enabling each user to run same interpreter.
### What type of PR is it? [Improvement] ### What is the Jira issue? https://issues.apache.org/jira/browse/ZEPPELIN-1210 ### How should this be tested? 1. Enable shiro to use authentication mode 1. Check `per user` in your interpreter tab 1. Run different paragraphs with different users 1. Run `%spark sc.version`, you will see the two `res0: ...` in your paragraphs ### Screenshots (if appropriate) ### Questions: * Does the licenses files need update? No * Is there breaking changes for older versions? No * Does this needs documentation? No Author: CloverHearts <[email protected]> Author: Jongyoul Lee <[email protected]> Closes #1265 from jongyoul/ZEPPELIN-1210 and squashes the following commits: 48a0d8e [Jongyoul Lee] Fixed ZEPPELIN-1542 Fixed flaky test e84703d [Jongyoul Lee] Fixed ZEPPELIN-1542 ad80951 [Jongyoul Lee] Fixed some wrong logic of getInterpreterInstanceKey cee39f4 [Jongyoul Lee] Fixed to pass shiro information to InterpreterFactory from ZeppelinServer 5e7da34 [Jongyoul Lee] Changed instanceKey and processKey for dealing with new UI d201950 [CloverHearts] fix eqeqeq issue for frontweb b18bff4 [CloverHearts] implement frontend for interpreter per user mode and misc mode 1f64e52 [CloverHearts] change default value for pernote and peruser 787a366 [CloverHearts] change Back-end test cases and member type (perNote, perUser) 8586e1f [CloverHearts] change ui for interpreter running Per x mode 0b5d671 [Jongyoul Lee] Fixed the style 960bde1 [Jongyoul Lee] Removed SecurityUtils.getPrincipal Added fromMessage.principal to get right user 01c7cf1 [Jongyoul Lee] Fixed NPE while testing ZeppelinSparkClusterTest 1fb50ab [Jongyoul Lee] Fixed NPE while testing ZeppelinSparkClusterTest d1c4344 [Jongyoul Lee] Fixed getEditorSetting for having users' info 12a27db [Jongyoul Lee] Fixed test after rebase 510942b [Jongyoul Lee] Fixed test after rebase cb66946 [Jongyoul Lee] Fixed test after rebase 18b39bd [Jongyoul Lee] Fixed test after rebase daa634f [Jongyoul Lee] Fixed some tests after rebase ed558be [Jongyoul Lee] Fixed some tests after rebase fa7fccb [Jongyoul Lee] Fixed destroying process of remoteInterpreterProcess 0a73241 [Jongyoul Lee] Fixed conflict while rebasing. df423d3 [Jongyoul Lee] Fixed NotebookRestApiTest b151366 [Jongyoul Lee] Fixed some codes after rebase a32afd7 [Jongyoul Lee] Fixed some tests 7b7eb78 [Jongyoul Lee] Fixed some tests 47cc668 [Jongyoul Lee] Fixed tests to use AuthenticationInfo 012cf99 [Jongyoul Lee] Fixed some mismatch after rebase 9a03d40 [Jongyoul Lee] Reverted some value to default ones 8589545 [Jongyoul Lee] Added option in UI ccbedc1 [Jongyoul Lee] WIP 94dfed2 [Jongyoul Lee] WIP 6480d1d [Jongyoul Lee] resolved conflicts Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/908b2a74 Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/908b2a74 Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/908b2a74 Branch: refs/heads/master Commit: 908b2a74ff59c231d4ba29de93812ea938f85f7f Parents: a3a2e4d Author: CloverHearts <[email protected]> Authored: Wed Oct 19 18:08:13 2016 +0900 Committer: Jongyoul Lee <[email protected]> Committed: Thu Oct 20 15:22:59 2016 +0900 ---------------------------------------------------------------------- .../zeppelin/interpreter/InterpreterGroup.java | 11 +- .../interpreter/remote/RemoteInterpreter.java | 1 + .../apache/zeppelin/rest/NotebookRestApi.java | 9 +- .../apache/zeppelin/server/ZeppelinServer.java | 2 +- .../apache/zeppelin/socket/NotebookServer.java | 70 ++++--- .../apache/zeppelin/utils/SecurityUtils.java | 6 + .../src/main/resources/log4j.properties | 25 +++ zeppelin-server/src/main/resources/shiro.ini | 11 +- .../zeppelin/rest/InterpreterRestApiTest.java | 22 +- .../zeppelin/rest/NotebookRestApiTest.java | 26 ++- .../zeppelin/rest/ZeppelinRestApiTest.java | 106 +++++----- .../zeppelin/rest/ZeppelinSparkClusterTest.java | 54 +++-- .../zeppelin/socket/NotebookServerTest.java | 12 +- .../interpreter-create/interpreter-create.html | 15 +- .../app/interpreter/interpreter.controller.js | 131 ++++++++++-- .../src/app/interpreter/interpreter.html | 194 ++++++++++++++--- .../interpreter/InterpreterFactory.java | 109 ++++++---- .../zeppelin/interpreter/InterpreterOption.java | 74 +++++-- .../interpreter/InterpreterSetting.java | 77 ++++--- .../java/org/apache/zeppelin/notebook/Note.java | 29 ++- .../org/apache/zeppelin/notebook/Notebook.java | 22 +- .../org/apache/zeppelin/notebook/Paragraph.java | 13 +- .../helium/HeliumApplicationFactoryTest.java | 47 +++-- .../interpreter/InterpreterFactoryTest.java | 57 +++-- .../notebook/NoteInterpreterLoaderTest.java | 88 ++++---- .../org/apache/zeppelin/notebook/NoteTest.java | 14 +- .../apache/zeppelin/notebook/NotebookTest.java | 209 ++++++++++--------- .../notebook/repo/NotebookRepoSyncTest.java | 93 +++++---- .../notebook/repo/VFSNotebookRepoTest.java | 10 +- .../zeppelin/search/LuceneSearchTest.java | 7 +- 30 files changed, 1029 insertions(+), 515 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java index ee53f8e..f3b158c 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/InterpreterGroup.java @@ -33,7 +33,7 @@ import org.apache.zeppelin.scheduler.SchedulerFactory; * and InterpreterGroup will have reference to these all interpreters. * * Remember, list of interpreters are dedicated to a note. - * (when InterpreterOption.perNoteSession==true) + * (when InterpreterOption.session==true) * So InterpreterGroup internally manages map of [noteId, list of interpreters] * * A InterpreterGroup runs on interpreter process. @@ -203,6 +203,14 @@ public class InterpreterGroup extends ConcurrentHashMap<String, List<Interpreter LOGGER.info("Destroy interpreter group " + getId() + " for note " + noteId); List<Interpreter> intpForNote = this.get(noteId); destroy(intpForNote); + + if (remoteInterpreterProcess != null) { + remoteInterpreterProcess.dereference(); + if (remoteInterpreterProcess.referenceCount() <= 0) { + remoteInterpreterProcess = null; + allInterpreterGroups.remove(id); + } + } } @@ -222,6 +230,7 @@ public class InterpreterGroup extends ConcurrentHashMap<String, List<Interpreter while (remoteInterpreterProcess.referenceCount() > 0) { remoteInterpreterProcess.dereference(); } + remoteInterpreterProcess = null; } allInterpreterGroups.remove(id); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java index 073b84b..e0cdaa3 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/interpreter/remote/RemoteInterpreter.java @@ -298,6 +298,7 @@ public class RemoteInterpreter extends Interpreter { if (logger.isDebugEnabled()) { logger.debug("st:\n{}", st); } + FormType form = getFormType(); RemoteInterpreterProcess interpreterProcess = getInterpreterProcess(); Client client = null; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java index b83a889..d9af812 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/NotebookRestApi.java @@ -177,7 +177,7 @@ public class NotebookRestApi { public Response bind(@PathParam("noteId") String noteId, String req) throws IOException { List<String> settingIdList = gson.fromJson(req, new TypeToken<List<String>>() { }.getType()); - notebook.bindInterpretersToNote(noteId, settingIdList); + notebook.bindInterpretersToNote(SecurityUtils.getPrincipal(), noteId, settingIdList); return new JsonResponse<>(Status.OK).build(); } @@ -458,7 +458,7 @@ public class NotebookRestApi { } AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal()); - note.removeParagraph(paragraphId); + note.removeParagraph(SecurityUtils.getPrincipal(), paragraphId); note.persist(subject); notebookServer.broadcastNote(note); @@ -599,6 +599,11 @@ public class NotebookRestApi { // handle params if presented handleParagraphParams(message, note, paragraph); + AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal()); + + paragraph.setAuthenticationInfo(subject); + note.persist(subject); + note.run(paragraph.getId()); return new JsonResponse<>(Status.OK).build(); } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java index c620235..de02fe0 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/server/ZeppelinServer.java @@ -89,7 +89,7 @@ public class ZeppelinServer extends Application { this.heliumApplicationFactory = new HeliumApplicationFactory(); this.schedulerFactory = new SchedulerFactory(); this.replFactory = new InterpreterFactory(conf, notebookWsServer, - notebookWsServer, heliumApplicationFactory, depResolver); + notebookWsServer, heliumApplicationFactory, depResolver, SecurityUtils.isAuthenticated()); this.notebookRepo = new NotebookRepoSync(conf); this.notebookIndex = new LuceneSearch(); this.notebookAuthorization = NotebookAuthorization.init(conf); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java index 2eee99e..969bdf9 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/socket/NotebookServer.java @@ -134,7 +134,7 @@ public class NotebookServer extends WebSocketServlet implements if (LOG.isTraceEnabled()) { LOG.trace("RECEIVE MSG = " + messagereceived); } - + String ticket = TicketContainer.instance.getTicket(messagereceived.principal); if (ticket != null && !ticket.equals(messagereceived.ticket)){ /* not to pollute logs, log instead of exception */ @@ -472,7 +472,8 @@ public class NotebookServer extends WebSocketServlet implements List<String> settingIdList = gson.fromJson(String.valueOf( fromMessage.data.get("selectedSettingIds")), new TypeToken<ArrayList<String>>() { }.getType()); - notebook().bindInterpretersToNote(noteId, settingIdList); + AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal); + notebook().bindInterpretersToNote(subject.getUser(), noteId, settingIdList); broadcastInterpreterBindings(noteId, InterpreterBindingUtils.getInterpreterBindings(notebook(), noteId)); } catch (Exception e) { @@ -600,6 +601,8 @@ public class NotebookServer extends WebSocketServlet implements return; } + String user = fromMessage.principal; + Note note = notebook.getNote(noteId); NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization(); if (note != null) { @@ -610,7 +613,7 @@ public class NotebookServer extends WebSocketServlet implements } addConnectionToNote(note.getId(), conn); conn.send(serializeMessage(new Message(OP.NOTE).put("note", note))); - sendAllAngularObjects(note, conn); + sendAllAngularObjects(note, user, conn); } else { conn.send(serializeMessage(new Message(OP.NOTE).put("note", null))); } @@ -619,6 +622,7 @@ public class NotebookServer extends WebSocketServlet implements private void sendHomeNote(NotebookSocket conn, HashSet<String> userAndRoles, Notebook notebook, Message fromMessage) throws IOException { String noteId = notebook.getConf().getString(ConfVars.ZEPPELIN_NOTEBOOK_HOMESCREEN); + String user = fromMessage.principal; Note note = null; if (noteId != null) { @@ -634,7 +638,7 @@ public class NotebookServer extends WebSocketServlet implements } addConnectionToNote(note.getId(), conn); conn.send(serializeMessage(new Message(OP.NOTE).put("note", note))); - sendAllAngularObjects(note, conn); + sendAllAngularObjects(note, user, conn); } else { removeConnectionFromAllNote(conn); conn.send(serializeMessage(new Message(OP.NOTE).put("note", null))); @@ -786,6 +790,8 @@ public class NotebookServer extends WebSocketServlet implements AuthenticationInfo subject = null; if (fromMessage.principal != null) { subject = new AuthenticationInfo(fromMessage.principal); + } else { + subject = new AuthenticationInfo("anonymous"); } note = notebook.importNote(noteJson, noteName, subject); note.persist(subject); @@ -804,7 +810,7 @@ public class NotebookServer extends WebSocketServlet implements String noteId = getOpenNoteId(conn); final Note note = notebook.getNote(noteId); NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization(); - AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal()); + AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal); if (!notebookAuthorization.isWriter(noteId, userAndRoles)) { permissionError(conn, "write", fromMessage.principal, userAndRoles, notebookAuthorization.getWriters(noteId)); @@ -813,7 +819,7 @@ public class NotebookServer extends WebSocketServlet implements /** We dont want to remove the last paragraph */ if (!note.isLastParagraph(paragraphId)) { - note.removeParagraph(paragraphId); + note.removeParagraph(subject.getUser(), paragraphId); note.persist(subject); broadcastNote(note); } @@ -869,6 +875,7 @@ public class NotebookServer extends WebSocketServlet implements String interpreterGroupId = (String) fromMessage.get("interpreterGroupId"); String varName = (String) fromMessage.get("name"); Object varValue = fromMessage.get("value"); + String user = fromMessage.principal; AngularObject ao = null; boolean global = false; // propagate change to (Remote) AngularObjectRegistry @@ -877,12 +884,12 @@ public class NotebookServer extends WebSocketServlet implements List<InterpreterSetting> settings = notebook.getInterpreterFactory() .getInterpreterSettings(note.getId()); for (InterpreterSetting setting : settings) { - if (setting.getInterpreterGroup(note.getId()) == null) { + if (setting.getInterpreterGroup(user, note.getId()) == null) { continue; } - if (interpreterGroupId.equals(setting.getInterpreterGroup(note.getId()).getId())) { + if (interpreterGroupId.equals(setting.getInterpreterGroup(user, note.getId()).getId())) { AngularObjectRegistry angularObjectRegistry = setting - .getInterpreterGroup(note.getId()).getAngularObjectRegistry(); + .getInterpreterGroup(user, note.getId()).getAngularObjectRegistry(); // first trying to get local registry ao = angularObjectRegistry.get(varName, noteId, paragraphId); @@ -919,12 +926,12 @@ public class NotebookServer extends WebSocketServlet implements List<InterpreterSetting> settings = notebook.getInterpreterFactory() .getInterpreterSettings(note.getId()); for (InterpreterSetting setting : settings) { - if (setting.getInterpreterGroup(n.getId()) == null) { + if (setting.getInterpreterGroup(user, n.getId()) == null) { continue; } - if (interpreterGroupId.equals(setting.getInterpreterGroup(n.getId()).getId())) { + if (interpreterGroupId.equals(setting.getInterpreterGroup(user, n.getId()).getId())) { AngularObjectRegistry angularObjectRegistry = setting - .getInterpreterGroup(n.getId()).getAngularObjectRegistry(); + .getInterpreterGroup(user, n.getId()).getAngularObjectRegistry(); this.broadcastExcept( n.getId(), new Message(OP.ANGULAR_OBJECT_UPDATE).put("angularObject", ao) @@ -1110,7 +1117,7 @@ public class NotebookServer extends WebSocketServlet implements String noteId = getOpenNoteId(conn); final Note note = notebook.getNote(noteId); NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization(); - AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal()); + AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal); if (!notebookAuthorization.isWriter(noteId, userAndRoles)) { permissionError(conn, "write", fromMessage.principal, userAndRoles, notebookAuthorization.getWriters(noteId)); @@ -1129,7 +1136,7 @@ public class NotebookServer extends WebSocketServlet implements String noteId = getOpenNoteId(conn); final Note note = notebook.getNote(noteId); NotebookAuthorization notebookAuthorization = notebook.getNotebookAuthorization(); - AuthenticationInfo subject = new AuthenticationInfo(SecurityUtils.getPrincipal()); + AuthenticationInfo subject = new AuthenticationInfo(fromMessage.principal); if (!notebookAuthorization.isWriter(noteId, userAndRoles)) { permissionError(conn, "write", fromMessage.principal, userAndRoles, notebookAuthorization.getWriters(noteId)); @@ -1181,14 +1188,9 @@ public class NotebookServer extends WebSocketServlet implements String text = (String) fromMessage.get("paragraph"); p.setText(text); p.setTitle((String) fromMessage.get("title")); - if (!fromMessage.principal.equals("anonymous")) { - AuthenticationInfo authenticationInfo = new AuthenticationInfo(fromMessage.principal, - fromMessage.ticket); - p.setAuthenticationInfo(authenticationInfo); - - } else { - p.setAuthenticationInfo(new AuthenticationInfo()); - } + AuthenticationInfo authenticationInfo = + new AuthenticationInfo(fromMessage.principal, fromMessage.ticket); + p.setAuthenticationInfo(authenticationInfo); Map<String, Object> params = (Map<String, Object>) fromMessage .get("params"); @@ -1513,7 +1515,7 @@ public class NotebookServer extends WebSocketServlet implements LOG.info("Job {} is finished", job.getId()); try { //TODO(khalid): may change interface for JobListener and pass subject from interpreter - note.persist(null); + note.persist(job instanceof Paragraph ? ((Paragraph) job).getAuthenticationInfo() : null); } catch (IOException e) { LOG.error(e.toString(), e); } @@ -1569,7 +1571,8 @@ public class NotebookServer extends WebSocketServlet implements return new NotebookInformationListener(this); } - private void sendAllAngularObjects(Note note, NotebookSocket conn) throws IOException { + private void sendAllAngularObjects(Note note, String user, NotebookSocket conn) + throws IOException { List<InterpreterSetting> settings = notebook().getInterpreterFactory().getInterpreterSettings(note.getId()); if (settings == null || settings.size() == 0) { @@ -1577,17 +1580,15 @@ public class NotebookServer extends WebSocketServlet implements } for (InterpreterSetting intpSetting : settings) { - AngularObjectRegistry registry = intpSetting.getInterpreterGroup(note.getId()) - .getAngularObjectRegistry(); + AngularObjectRegistry registry = + intpSetting.getInterpreterGroup(user, note.getId()).getAngularObjectRegistry(); List<AngularObject> objects = registry.getAllWithGlobal(note.getId()); for (AngularObject object : objects) { - conn.send(serializeMessage(new Message(OP.ANGULAR_OBJECT_UPDATE) - .put("angularObject", object) - .put("interpreterGroupId", - intpSetting.getInterpreterGroup(note.getId()).getId()) - .put("noteId", note.getId()) - .put("paragraphId", object.getParagraphId()) - )); + conn.send(serializeMessage( + new Message(OP.ANGULAR_OBJECT_UPDATE).put("angularObject", object) + .put("interpreterGroupId", + intpSetting.getInterpreterGroup(user, note.getId()).getId()) + .put("noteId", note.getId()).put("paragraphId", object.getParagraphId()))); } } } @@ -1654,9 +1655,10 @@ public class NotebookServer extends WebSocketServlet implements String paragraphId = (String) fromMessage.get("paragraphId"); String replName = (String) fromMessage.get("magic"); String noteId = getOpenNoteId(conn); + String user = fromMessage.principal; Message resp = new Message(OP.EDITOR_SETTING); resp.put("paragraphId", paragraphId); - resp.put("editor", notebook().getInterpreterFactory().getEditorSetting(noteId, replName)); + resp.put("editor", notebook().getInterpreterFactory().getEditorSetting(user, noteId, replName)); conn.send(serializeMessage(resp)); return; } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java index f9e5929..d81d2e6 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/utils/SecurityUtils.java @@ -119,4 +119,10 @@ public class SecurityUtils { return roles; } + /** + * Checked if shiro enabled or not + */ + public static boolean isAuthenticated() { + return org.apache.shiro.SecurityUtils.getSubject().isAuthenticated(); + } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/main/resources/log4j.properties ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/resources/log4j.properties b/zeppelin-server/src/main/resources/log4j.properties new file mode 100644 index 0000000..2f64407 --- /dev/null +++ b/zeppelin-server/src/main/resources/log4j.properties @@ -0,0 +1,25 @@ +# +# 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. +# + +log4j.rootLogger = INFO, stdout + +log4j.appender.stdout = org.apache.log4j.ConsoleAppender +log4j.appender.stdout.layout = org.apache.log4j.PatternLayout +log4j.appender.stdout.layout.ConversionPattern=%5p [%d] ({%t} %F[%M]:%L) - %m%n + +log4j.additivity.org.apache.zeppelin.interpreter = false +log4j.logger.org.apache.zeppelin.interpreter = DEBUG, stdout http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/main/resources/shiro.ini ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/resources/shiro.ini b/zeppelin-server/src/main/resources/shiro.ini index 371a44e..050c9d9 100644 --- a/zeppelin-server/src/main/resources/shiro.ini +++ b/zeppelin-server/src/main/resources/shiro.ini @@ -18,14 +18,19 @@ [users] # List of users with their password allowed to access Zeppelin. # To use a different strategy (LDAP / Database / ...) check the shiro doc at http://shiro.apache.org/configuration.html#Configuration-INISections -admin = password +admin = password, admin +user1 = user1, role1 [urls] - # anon means the access is anonymous. # authcBasic means Basic Auth Security # To enfore security, comment the line below and uncomment the next one /** = anon -#/** = authcBasic +#/** = authc +[roles] +role1 = * +role2 = * +role3 = * +admin = * http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java index c767eb0..6d4fb2c 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/InterpreterRestApiTest.java @@ -30,7 +30,9 @@ import org.apache.zeppelin.notebook.Note; import org.apache.zeppelin.notebook.Paragraph; import org.apache.zeppelin.scheduler.Job.Status; import org.apache.zeppelin.server.ZeppelinServer; +import org.apache.zeppelin.user.AuthenticationInfo; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; @@ -47,6 +49,7 @@ import static org.junit.Assert.*; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class InterpreterRestApiTest extends AbstractTestRestApi { Gson gson = new Gson(); + AuthenticationInfo anonymous; @BeforeClass public static void init() throws Exception { @@ -58,6 +61,11 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { AbstractTestRestApi.shutDown(); } + @Before + public void setUp() { + anonymous = new AuthenticationInfo("anonymous"); + } + @Test public void getAvailableInterpreters() throws IOException { // when @@ -90,7 +98,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { String jsonRequest = "{\"name\":\"md2\",\"group\":\"md\",\"properties\":{\"propname\":\"propvalue\"}," + "\"interpreterGroup\":[{\"class\":\"org.apache.zeppelin.markdown.Markdown\",\"name\":\"md\"}]," + "\"dependencies\":[]," + - "\"option\": { \"remote\": true, \"perNoteSession\": false }}"; + "\"option\": { \"remote\": true, \"session\": false }}"; PostMethod post = httpPost("/interpreter/setting/", jsonRequest); LOG.info("testSettingCRUD create response\n" + post.getResponseBodyAsString()); assertThat("test create method:", post, isCreated()); @@ -106,7 +114,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { jsonRequest = "{\"name\":\"md2\",\"group\":\"md\",\"properties\":{\"propname\":\"Otherpropvalue\"}," + "\"interpreterGroup\":[{\"class\":\"org.apache.zeppelin.markdown.Markdown\",\"name\":\"md\"}]," + "\"dependencies\":[]," + - "\"option\": { \"remote\": true, \"perNoteSession\": false }}"; + "\"option\": { \"remote\": true, \"session\": false }}"; PutMethod put = httpPut("/interpreter/setting/" + newSettingId, jsonRequest); LOG.info("testSettingCRUD update response\n" + put.getResponseBodyAsString()); assertThat("test update method:", put, isAllowed()); @@ -131,7 +139,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { @Test public void testInterpreterAutoBinding() throws IOException { // create note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); // check interpreter is binded GetMethod get = httpGet("/notebook/interpreter/bind/" + note.getId()); @@ -144,13 +152,13 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { get.releaseConnection(); //cleanup - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testInterpreterRestart() throws IOException, InterruptedException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); note.addParagraph(); Paragraph p = note.getLastParagraph(); Map config = p.getConfig(); @@ -159,6 +167,7 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { // run markdown paragraph p.setConfig(config); p.setText("%md markdown"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); while (p.getStatus() != Status.FINISHED) { Thread.sleep(100); @@ -181,13 +190,14 @@ public class InterpreterRestApiTest extends AbstractTestRestApi { p = note.addParagraph(); p.setConfig(config); p.setText("%md markdown restarted"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); while (p.getStatus() != Status.FINISHED) { Thread.sleep(100); } assertEquals("<p>markdown restarted</p>\n", p.getResult().message()); //cleanup - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java index d7f55f5..9383569 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/NotebookRestApiTest.java @@ -28,7 +28,9 @@ import org.apache.zeppelin.notebook.Note; import org.apache.zeppelin.notebook.NotebookAuthorization; import org.apache.zeppelin.notebook.NotebookAuthorizationInfoSaving; import org.apache.zeppelin.server.ZeppelinServer; +import org.apache.zeppelin.user.AuthenticationInfo; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; @@ -49,6 +51,7 @@ import static org.junit.Assert.assertThat; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class NotebookRestApiTest extends AbstractTestRestApi { Gson gson = new Gson(); + AuthenticationInfo anonymous; @BeforeClass public static void init() throws Exception { @@ -60,9 +63,14 @@ public class NotebookRestApiTest extends AbstractTestRestApi { AbstractTestRestApi.shutDown(); } + @Before + public void setUp() { + anonymous = new AuthenticationInfo("anonymous"); + } + @Test public void testPermissions() throws IOException { - Note note1 = ZeppelinServer.notebook.createNote(null); + Note note1 = ZeppelinServer.notebook.createNote(anonymous); // Set only readers String jsonRequest = "{\"readers\":[\"admin-team\"],\"owners\":[]," + "\"writers\":[]}"; @@ -85,7 +93,7 @@ public class NotebookRestApiTest extends AbstractTestRestApi { get.releaseConnection(); - Note note2 = ZeppelinServer.notebook.createNote(null); + Note note2 = ZeppelinServer.notebook.createNote(anonymous); // Set only writers jsonRequest = "{\"readers\":[],\"owners\":[]," + "\"writers\":[\"admin-team\"]}"; @@ -119,14 +127,14 @@ public class NotebookRestApiTest extends AbstractTestRestApi { assertEquals(authInfo.get("owners"), Lists.newArrayList()); get.releaseConnection(); //cleanup - ZeppelinServer.notebook.removeNote(note1.getId(), null); - ZeppelinServer.notebook.removeNote(note2.getId(), null); + ZeppelinServer.notebook.removeNote(note1.getId(), anonymous); + ZeppelinServer.notebook.removeNote(note2.getId(), anonymous); } @Test public void testGetNoteParagraphJobStatus() throws IOException { - Note note1 = ZeppelinServer.notebook.createNote(null); + Note note1 = ZeppelinServer.notebook.createNote(anonymous); note1.addParagraph(); String paragraphId = note1.getLastParagraph().getId(); @@ -142,13 +150,13 @@ public class NotebookRestApiTest extends AbstractTestRestApi { assertEquals(paragraphStatus.get("status"), "READY"); //cleanup - ZeppelinServer.notebook.removeNote(note1.getId(), null); + ZeppelinServer.notebook.removeNote(note1.getId(), anonymous); } @Test public void testCloneNotebook() throws IOException { - Note note1 = ZeppelinServer.notebook.createNote(null); + Note note1 = ZeppelinServer.notebook.createNote(anonymous); PostMethod post = httpPost("/notebook/" + note1.getId(), ""); LOG.info("testCloneNotebook response\n" + post.getResponseBodyAsString()); assertThat(post, isCreated()); @@ -167,8 +175,8 @@ public class NotebookRestApiTest extends AbstractTestRestApi { get.releaseConnection(); //cleanup - ZeppelinServer.notebook.removeNote(note1.getId(), null); - ZeppelinServer.notebook.removeNote(clonedNotebookId, null); + ZeppelinServer.notebook.removeNote(note1.getId(), anonymous); + ZeppelinServer.notebook.removeNote(clonedNotebookId, anonymous); } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java index ffcbf2a..c2606f8 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinRestApiTest.java @@ -34,6 +34,7 @@ import org.apache.zeppelin.scheduler.Job.Status; import org.apache.zeppelin.server.ZeppelinServer; import org.apache.zeppelin.user.AuthenticationInfo; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; @@ -51,6 +52,7 @@ import static org.junit.Assert.*; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ZeppelinRestApiTest extends AbstractTestRestApi { Gson gson = new Gson(); + AuthenticationInfo anonymous; @BeforeClass public static void init() throws Exception { @@ -62,6 +64,11 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { AbstractTestRestApi.shutDown(); } + @Before + public void setUp() { + anonymous = new AuthenticationInfo("anonymous"); + } + /*** * ROOT API TEST ***/ @@ -78,7 +85,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { public void testGetNotebookInfo() throws IOException { LOG.info("testGetNotebookInfo"); // Create note to get info - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName("note"); Paragraph paragraph = note.addParagraph(); @@ -87,7 +94,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { paragraph.setConfig(config); String paragraphText = "%md This is my new paragraph in my new note"; paragraph.setText(paragraphText); - note.persist(null); + note.persist(anonymous); String sourceNoteID = note.getId(); GetMethod get = httpGet("/notebook/" + sourceNoteID); @@ -106,7 +113,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertTrue(paragraphs.size() > 0); assertEquals(paragraphText, paragraphs.get(0).get("text")); // - ZeppelinServer.notebook.removeNote(sourceNoteID, null); + ZeppelinServer.notebook.removeNote(sourceNoteID, anonymous); } @Test @@ -156,7 +163,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertTrue("paragraph text check failed", p.getText().startsWith("text")); } // cleanup - ZeppelinServer.notebook.removeNote(newNotebookId, null); + ZeppelinServer.notebook.removeNote(newNotebookId, anonymous); post.releaseConnection(); } @@ -183,7 +190,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { } assertEquals("compare note name", expectedNoteName, newNoteName); // cleanup - ZeppelinServer.notebook.removeNote(newNotebookId, null); + ZeppelinServer.notebook.removeNote(newNotebookId, anonymous); post.releaseConnection(); } @@ -192,7 +199,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { public void testDeleteNote() throws IOException { LOG.info("testDeleteNote"); //Create note and get ID - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); String noteId = note.getId(); testDeleteNotebook(noteId); } @@ -208,7 +215,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { @Test public void testExportNotebook() throws IOException { LOG.info("testExportNotebook"); - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName("source note for export"); Paragraph paragraph = note.addParagraph(); @@ -216,7 +223,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { config.put("enabled", true); paragraph.setConfig(config); paragraph.setText("%md This is my new paragraph in my new note"); - note.persist(null); + note.persist(anonymous); String sourceNoteID = note.getId(); // Call export Notebook REST API GetMethod get = httpGet("/notebook/export/" + sourceNoteID); @@ -230,7 +237,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { String exportJSON = (String) resp.get("body"); assertNotNull("Can not find new notejson", exportJSON); LOG.info("export JSON:=" + exportJSON); - ZeppelinServer.notebook.removeNote(sourceNoteID, null); + ZeppelinServer.notebook.removeNote(sourceNoteID, anonymous); get.releaseConnection(); } @@ -241,7 +248,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { String noteName = "source note for import"; LOG.info("testImortNotebook"); // create test notebook - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName(noteName); Paragraph paragraph = note.addParagraph(); @@ -249,7 +256,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { config.put("enabled", true); paragraph.setConfig(config); paragraph.setText("%md This is my new paragraph in my new note"); - note.persist(null); + note.persist(anonymous); String sourceNoteID = note.getId(); // get note content as JSON String oldJson = getNoteContent(sourceNoteID); @@ -267,8 +274,8 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertEquals("Compare paragraphs count", note.getParagraphs().size(), newNote.getParagraphs() .size()); // cleanup - ZeppelinServer.notebook.removeNote(note.getId(), null); - ZeppelinServer.notebook.removeNote(newNote.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); + ZeppelinServer.notebook.removeNote(newNote.getId(), anonymous); importPost.releaseConnection(); } @@ -303,7 +310,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { public void testCloneNotebook() throws IOException, CloneNotSupportedException, IllegalArgumentException { LOG.info("testCloneNotebook"); // Create note to clone - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName("source note for clone"); Paragraph paragraph = note.addParagraph(); @@ -311,7 +318,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { config.put("enabled", true); paragraph.setConfig(config); paragraph.setText("%md This is my new paragraph in my new note"); - note.persist(null); + note.persist(anonymous); String sourceNoteID = note.getId(); String noteName = "clone Note Name"; @@ -331,8 +338,8 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertEquals("Compare note names", noteName, newNote.getName()); assertEquals("Compare paragraphs count", note.getParagraphs().size(), newNote.getParagraphs().size()); //cleanup - ZeppelinServer.notebook.removeNote(note.getId(), null); - ZeppelinServer.notebook.removeNote(newNote.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); + ZeppelinServer.notebook.removeNote(newNote.getId(), anonymous); post.releaseConnection(); } @@ -354,7 +361,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { public void testNoteJobs() throws IOException, InterruptedException { LOG.info("testNoteJobs"); // Create note to run test. - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName("note for run test"); Paragraph paragraph = note.addParagraph(); @@ -364,7 +371,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { paragraph.setConfig(config); paragraph.setText("%md This is test paragraph."); - note.persist(null); + note.persist(anonymous); String noteID = note.getId(); note.runAll(); @@ -402,14 +409,14 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { Thread.sleep(1000); //cleanup - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testGetNotebookJob() throws IOException, InterruptedException { LOG.info("testGetNotebookJob"); // Create note to run test. - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName("note for run test"); Paragraph paragraph = note.addParagraph(); @@ -419,7 +426,8 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { paragraph.setConfig(config); paragraph.setText("%sh sleep 1"); - note.persist(null); + paragraph.setAuthenticationInfo(anonymous); + note.persist(anonymous); String noteID = note.getId(); note.runAll(); @@ -455,14 +463,14 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { } } - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testRunParagraphWithParams() throws IOException, InterruptedException { LOG.info("testRunParagraphWithParams"); // Create note to run test. - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); assertNotNull("can't create new note", note); note.setName("note for run test"); Paragraph paragraph = note.addParagraph(); @@ -472,7 +480,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { paragraph.setConfig(config); paragraph.setText("%spark\nval param = z.input(\"param\").toString\nprintln(param)"); - note.persist(null); + note.persist(anonymous); String noteID = note.getId(); note.runAll(); @@ -500,13 +508,13 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertEquals("world", params.get("param2")); //cleanup - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test - public void testCronJobs() throws InterruptedException, IOException{ + public void testJobs() throws InterruptedException, IOException{ // create a note and a paragraph - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); note.setName("note for run test"); Paragraph paragraph = note.addParagraph(); @@ -550,18 +558,18 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { DeleteMethod deleteCron = httpDelete("/notebook/cron/" + note.getId()); assertThat("", deleteCron, isAllowed()); deleteCron.releaseConnection(); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testRegressionZEPPELIN_527() throws IOException { - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); note.setName("note for run test"); Paragraph paragraph = note.addParagraph(); paragraph.setText("%spark\nval param = z.input(\"param\").toString\nprintln(param)"); - note.persist(null); + note.persist(anonymous); GetMethod getNoteJobs = httpGet("/notebook/job/" + note.getId()); assertThat("test notebook jobs run:", getNoteJobs, isAllowed()); @@ -572,12 +580,12 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertFalse(body.get(0).containsKey("finished")); getNoteJobs.releaseConnection(); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testInsertParagraph() throws IOException { - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); String jsonRequest = "{\"title\": \"title1\", \"text\": \"text1\"}"; PostMethod post = httpPost("/notebook/" + note.getId() + "/paragraph", jsonRequest); @@ -612,17 +620,17 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertEquals("title2", paragraphAtIdx0.getTitle()); assertEquals("text2", paragraphAtIdx0.getText()); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testGetParagraph() throws IOException { - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); Paragraph p = note.addParagraph(); p.setTitle("hello"); p.setText("world"); - note.persist(null); + note.persist(anonymous); GetMethod get = httpGet("/notebook/" + note.getId() + "/paragraph/" + p.getId()); LOG.info("testGetParagraph response\n" + get.getResponseBodyAsString()); @@ -641,12 +649,12 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertEquals("hello", body.get("title")); assertEquals("world", body.get("text")); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testMoveParagraph() throws IOException { - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); Paragraph p = note.addParagraph(); p.setTitle("title1"); @@ -656,7 +664,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { p2.setTitle("title2"); p2.setText("text2"); - note.persist(null); + note.persist(anonymous); PostMethod post = httpPost("/notebook/" + note.getId() + "/paragraph/" + p2.getId() + "/move/" + 0, ""); assertThat("Test post method: ", post, isAllowed()); @@ -673,18 +681,18 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { assertThat("Test post method: ", post2, isBadRequest()); post.releaseConnection(); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void testDeleteParagraph() throws IOException { - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); Paragraph p = note.addParagraph(); p.setTitle("title1"); p.setText("text1"); - note.persist(null); + note.persist(anonymous); DeleteMethod delete = httpDelete("/notebook/" + note.getId() + "/paragraph/" + p.getId()); assertThat("Test delete method: ", delete, isAllowed()); @@ -694,7 +702,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { Paragraph retrParagrah = retrNote.getParagraph(p.getId()); assertNull("paragraph should be deleted", retrParagrah); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test @@ -710,12 +718,12 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { String username = body.get("principal"); getSecurityTicket.releaseConnection(); - Note note1 = ZeppelinServer.notebook.createNote(null); + Note note1 = ZeppelinServer.notebook.createNote(anonymous); String jsonRequest = "{\"title\": \"title1\", \"text\": \"ThisIsToTestSearchMethodWithPermissions 1\"}"; PostMethod postNotebookText = httpPost("/notebook/" + note1.getId() + "/paragraph", jsonRequest); postNotebookText.releaseConnection(); - Note note2 = ZeppelinServer.notebook.createNote(null); + Note note2 = ZeppelinServer.notebook.createNote(anonymous); jsonRequest = "{\"title\": \"title1\", \"text\": \"ThisIsToTestSearchMethodWithPermissions 2\"}"; postNotebookText = httpPost("/notebook/" + note2.getId() + "/paragraph", jsonRequest); postNotebookText.releaseConnection(); @@ -757,13 +765,13 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { getPermission.releaseConnection(); } searchNotebook.releaseConnection(); - ZeppelinServer.notebook.removeNote(note1.getId(), null); - ZeppelinServer.notebook.removeNote(note2.getId(), null); + ZeppelinServer.notebook.removeNote(note1.getId(), anonymous); + ZeppelinServer.notebook.removeNote(note2.getId(), anonymous); } @Test public void testTitleSearch() throws IOException { - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); String jsonRequest = "{\"title\": \"testTitleSearchOfParagraph\", \"text\": \"ThisIsToTestSearchMethodWithTitle \"}"; PostMethod postNotebookText = httpPost("/notebook/" + note.getId() + "/paragraph", jsonRequest); postNotebookText.releaseConnection(); @@ -784,7 +792,7 @@ public class ZeppelinRestApiTest extends AbstractTestRestApi { } assertEquals("Paragraph title hits must be at-least one", true, numberOfTitleHits >= 1); searchNotebook.releaseConnection(); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java index 5084ae7..740ef40 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/rest/ZeppelinSparkClusterTest.java @@ -31,7 +31,9 @@ import org.apache.zeppelin.notebook.Note; import org.apache.zeppelin.notebook.Paragraph; import org.apache.zeppelin.scheduler.Job.Status; import org.apache.zeppelin.server.ZeppelinServer; +import org.apache.zeppelin.user.AuthenticationInfo; import org.junit.AfterClass; +import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -43,6 +45,7 @@ import com.google.gson.Gson; */ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { Gson gson = new Gson(); + AuthenticationInfo anonymous; @BeforeClass public static void init() throws Exception { @@ -54,6 +57,11 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { AbstractTestRestApi.shutDown(); } + @Before + public void setUp() { + anonymous = new AuthenticationInfo("anonymous"); + } + private void waitForFinish(Paragraph p) { while (p.getStatus() != Status.FINISHED && p.getStatus() != Status.ERROR @@ -69,7 +77,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { @Test public void basicRDDTransformationAndActionTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); // run markdown paragraph, again Paragraph p = note.addParagraph(); @@ -77,17 +85,18 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { config.put("enabled", true); p.setConfig(config); p.setText("%spark print(sc.parallelize(1 to 10).reduce(_ + _))"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); assertEquals("55", p.getResult().message()); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void sparkSQLTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); int sparkVersion = getSparkVersionNumber(note); // DataFrame API is available from spark 1.3 if (sparkVersion >= 13) { @@ -98,6 +107,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setConfig(config); p.setText("%spark val df=sqlContext.createDataFrame(Seq((\"hello\",20)))\n" + "df.collect()"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -111,6 +121,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setConfig(config); p.setText("%spark val df=sqlContext.createDataFrame(Seq((\"hello\",20)))\n" + "z.show(df)"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -125,20 +136,21 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setConfig(config); p.setText("%spark val ds=spark.createDataset(Seq((\"hello\",20)))\n" + "z.show(ds)"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); assertEquals(InterpreterResult.Type.TABLE, p.getResult().type()); assertEquals("_1\t_2\nhello\t20\n", p.getResult().message()); } - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } } @Test public void sparkRTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); int sparkVersion = getSparkVersionNumber(note); if (isSparkR() && sparkVersion >= 14) { // sparkr supported from 1.4.0 @@ -165,19 +177,20 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { "df <- createDataFrame(" + sqlContextName + ", localDF)\n" + "count(df)" ); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); System.err.println("sparkRTest=" + p.getResult().message()); assertEquals(Status.FINISHED, p.getStatus()); assertEquals("[1] 3", p.getResult().message()); } - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void pySparkTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); note.setName("note"); int sparkVersion = getSparkVersionNumber(note); @@ -188,6 +201,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { config.put("enabled", true); p.setConfig(config); p.setText("%pyspark print(sc.parallelize(range(1, 11)).reduce(lambda a, b: a + b))"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -201,6 +215,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setText("%pyspark from pyspark.sql import Row\n" + "df=sqlContext.createDataFrame([Row(id=1, age=20)])\n" + "df.collect()"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -214,6 +229,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setText("%pyspark from pyspark.sql import Row\n" + "df=sqlContext.createDataFrame([Row(id=1, age=20)])\n" + "z.show(df)"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -228,6 +244,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setConfig(config); p.setText("%pyspark sqlContext.udf.register(\"f1\", lambda x: len(x))\n" + "sqlContext.sql(\"select f1(\\\"abc\\\") as len\").collect()"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -242,6 +259,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setText("%pyspark from pyspark.sql import Row\n" + "df=sqlContext.createDataFrame([Row(id=1, age=20)])\n" + "df.collect()"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); @@ -255,19 +273,20 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { // use SQLContext to register UDF but use this UDF through SparkSession p.setText("%pyspark sqlContext.udf.register(\"f1\", lambda x: len(x))\n" + "spark.sql(\"select f1(\\\"abc\\\") as len\").collect()"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); assertEquals("[Row(len=u'3')]\n", p.getResult().message()); } } - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void pySparkAutoConvertOptionTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); note.setName("note"); int sparkVersionNumber = getSparkVersionNumber(note); @@ -286,33 +305,37 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { p.setText("%pyspark\nfrom pyspark.sql.functions import *\n" + "print(" + sqlContextName + ".range(0, 10).withColumn('uniform', rand(seed=10) * 3.14).count())"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); assertEquals("10\n", p.getResult().message()); } - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void zRunTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); Paragraph p0 = note.addParagraph(); Map config0 = p0.getConfig(); config0.put("enabled", true); p0.setConfig(config0); p0.setText("%spark z.run(1)"); + p0.setAuthenticationInfo(anonymous); Paragraph p1 = note.addParagraph(); Map config1 = p1.getConfig(); config1.put("enabled", true); p1.setConfig(config1); p1.setText("%spark val a=10"); + p1.setAuthenticationInfo(anonymous); Paragraph p2 = note.addParagraph(); Map config2 = p2.getConfig(); config2.put("enabled", true); p2.setConfig(config2); p2.setText("%spark print(a)"); + p2.setAuthenticationInfo(anonymous); note.run(p0.getId()); waitForFinish(p0); @@ -323,13 +346,13 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { assertEquals(Status.FINISHED, p2.getStatus()); assertEquals("10", p2.getResult().message()); - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } @Test public void pySparkDepLoaderTest() throws IOException { // create new note - Note note = ZeppelinServer.notebook.createNote(null); + Note note = ZeppelinServer.notebook.createNote(anonymous); int sparkVersionNumber = getSparkVersionNumber(note); if (isPyspark() && sparkVersionNumber >= 14) { @@ -350,6 +373,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { config.put("enabled", true); p0.setConfig(config); p0.setText("%dep z.load(\"com.databricks:spark-csv_2.11:1.2.0\")"); + p0.setAuthenticationInfo(anonymous); note.run(p0.getId()); waitForFinish(p0); assertEquals(Status.FINISHED, p0.getStatus()); @@ -370,13 +394,14 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { "from pyspark.sql import SQLContext\n" + "print(" + sqlContextName + ".read.format('com.databricks.spark.csv')" + ".load('"+ tmpFile.getAbsolutePath() +"').count())"); + p1.setAuthenticationInfo(anonymous); note.run(p1.getId()); waitForFinish(p1); assertEquals(Status.FINISHED, p1.getStatus()); assertEquals("2\n", p1.getResult().message()); } - ZeppelinServer.notebook.removeNote(note.getId(), null); + ZeppelinServer.notebook.removeNote(note.getId(), anonymous); } /** @@ -390,6 +415,7 @@ public class ZeppelinSparkClusterTest extends AbstractTestRestApi { config.put("enabled", true); p.setConfig(config); p.setText("%spark print(sc.version)"); + p.setAuthenticationInfo(anonymous); note.run(p.getId()); waitForFinish(p); assertEquals(Status.FINISHED, p.getStatus()); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java index 01a24e2..caac043 100644 --- a/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java +++ b/zeppelin-server/src/test/java/org/apache/zeppelin/socket/NotebookServerTest.java @@ -31,6 +31,7 @@ import org.apache.zeppelin.notebook.socket.Message; import org.apache.zeppelin.notebook.socket.Message.OP; import org.apache.zeppelin.rest.AbstractTestRestApi; import org.apache.zeppelin.server.ZeppelinServer; +import org.apache.zeppelin.user.AuthenticationInfo; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; @@ -57,6 +58,7 @@ public class NotebookServerTest extends AbstractTestRestApi { private static NotebookServer notebookServer; private static Gson gson; private HttpServletRequest mockRequest; + private AuthenticationInfo anonymous; @BeforeClass public static void init() throws Exception { @@ -74,6 +76,7 @@ public class NotebookServerTest extends AbstractTestRestApi { @Before public void setUp() { mockRequest = mock(HttpServletRequest.class); + anonymous = new AuthenticationInfo("anonymous"); } @Test @@ -94,14 +97,14 @@ public class NotebookServerTest extends AbstractTestRestApi { @Test public void testMakeSureNoAngularObjectBroadcastToWebsocketWhoFireTheEvent() throws IOException { // create a notebook - Note note1 = notebook.createNote(null); + Note note1 = notebook.createNote(anonymous); // get reference to interpreterGroup InterpreterGroup interpreterGroup = null; List<InterpreterSetting> settings = notebook.getInterpreterFactory().getInterpreterSettings(note1.getId()); for (InterpreterSetting setting : settings) { if (setting.getName().equals("md")) { - interpreterGroup = setting.getInterpreterGroup("sharedProcess"); + interpreterGroup = setting.getInterpreterGroup("anonymous", "sharedProcess"); break; } } @@ -109,6 +112,7 @@ public class NotebookServerTest extends AbstractTestRestApi { // start interpreter process Paragraph p1 = note1.addParagraph(); p1.setText("%md start remote interpreter process"); + p1.setAuthenticationInfo(anonymous); note1.run(p1.getId()); // add angularObject @@ -144,7 +148,7 @@ public class NotebookServerTest extends AbstractTestRestApi { verify(sock1, times(0)).send(anyString()); verify(sock2, times(1)).send(anyString()); - notebook.removeNote(note1.getId(), null); + notebook.removeNote(note1.getId(), anonymous); } @Test @@ -167,7 +171,7 @@ public class NotebookServerTest extends AbstractTestRestApi { assertNotEquals(null, notebook.getNote(note.getId())); assertEquals("Test Zeppelin notebook import", notebook.getNote(note.getId()).getName()); assertEquals("Test paragraphs import", notebook.getNote(note.getId()).getParagraphs().get(0).getText()); - notebook.removeNote(note.getId(), null); + notebook.removeNote(note.getId(), anonymous); } @Test http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html index d0e0749..2638dd8 100644 --- a/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html +++ b/zeppelin-web/src/app/interpreter/interpreter-create/interpreter-create.html @@ -37,23 +37,31 @@ limitations under the License. <div> <h5>Option</h5> + <span class="checkbox input-group"> + <label><input type="checkbox" style="width:0%;height:0%" id="perNote" ng-model="newInterpreterSetting.option.perNote"/> + perNote </label> + </span> + <span class="checkbox input-group"> + <label><input type="checkbox" style="width:0%;height:0%" id="perUser" ng-model="newInterpreterSetting.option.perUser"/> + perUser</label> + </span> <span class="btn-group"> <button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown"> - {{getSessionOption(setting.id)}} <span class="caret"></span> + {{getSessionOption(newInterpreterSetting.id)}} <span class="caret"></span> </button> <ul class="dropdown-menu" role="menu"> <li> <a style="cursor:pointer" tooltip="Single interpreter instance are shared across notes" - ng-click="setSessionOption(setting.id, 'shared')"> + ng-click="setSessionOption(newInterpreterSetting.id, 'shared')"> shared </a> </li> <li> <a style="cursor:pointer" tooltip="Separate Interpreter instance for each note" - ng-click="setSessionOption(setting.id, 'scoped')"> + ng-click="setSessionOption(newInterpreterSetting.id, 'scoped')"> scoped </a> </li> @@ -66,7 +74,6 @@ limitations under the License. </li> </ul> </span> - <span>Interpreter for note</span> </div> <div class="row interpreter" style="margin-top: 5px;"> http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-web/src/app/interpreter/interpreter.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/interpreter/interpreter.controller.js b/zeppelin-web/src/app/interpreter/interpreter.controller.js index 3fe355f..0669ff8 100644 --- a/zeppelin-web/src/app/interpreter/interpreter.controller.js +++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js @@ -16,9 +16,9 @@ angular.module('zeppelinWebApp').controller('InterpreterCtrl', InterpreterCtrl); - InterpreterCtrl.$inject = ['$scope', '$http', 'baseUrlSrv', 'ngToast', '$timeout', '$route']; + InterpreterCtrl.$inject = ['$rootScope', '$scope', '$http', 'baseUrlSrv', 'ngToast', '$timeout', '$route']; - function InterpreterCtrl($scope, $http, baseUrlSrv, ngToast, $timeout, $route) { + function InterpreterCtrl($rootScope, $scope, $http, baseUrlSrv, ngToast, $timeout, $route) { var interpreterSettingsTmp = []; $scope.interpreterSettings = []; $scope.availableInterpreters = {}; @@ -156,7 +156,7 @@ interpreterSettingsTmp[index] = angular.copy($scope.interpreterSettings[index]); }; - $scope.setSessionOption = function(settingId, sessionOption) { + $scope.setPerNoteOption = function(settingId, sessionOption) { var option; if (settingId === undefined) { option = $scope.newInterpreterSetting.option; @@ -167,18 +167,21 @@ } if (sessionOption === 'isolated') { - option.perNoteSession = false; - option.perNoteProcess = true; + option.perNote = sessionOption; + option.session = false; + option.process = true; } else if (sessionOption === 'scoped') { - option.perNoteSession = true; - option.perNoteProcess = false; + option.perNote = sessionOption; + option.session = true; + option.process = false; } else { - option.perNoteSession = false; - option.perNoteProcess = false; + option.perNote = 'shared'; + option.session = false; + option.process = false; } }; - $scope.getSessionOption = function(settingId) { + $scope.setPerUserOption = function(settingId, sessionOption) { var option; if (settingId === undefined) { option = $scope.newInterpreterSetting.option; @@ -187,15 +190,115 @@ var setting = $scope.interpreterSettings[index]; option = setting.option; } - if (option.perNoteSession) { + + if (sessionOption === 'isolated') { + option.perUser = sessionOption; + option.session = false; + option.process = true; + } else if (sessionOption === 'scoped') { + option.perUser = sessionOption; + option.session = true; + option.process = false; + } else { + option.perUser = 'shared'; + option.session = false; + option.process = false; + } + }; + + $scope.getPerNoteOption = function(settingId) { + var option; + if (settingId === undefined) { + option = $scope.newInterpreterSetting.option; + } else { + var index = _.findIndex($scope.interpreterSettings, {'id': settingId}); + var setting = $scope.interpreterSettings[index]; + option = setting.option; + } + + if (option.perNote === 'scoped') { + return 'scoped'; + } else if (option.perNote === 'isolated') { + return 'isolated'; + } else { + return 'shared'; + } + }; + + $scope.getPerUserOption = function(settingId) { + var option; + if (settingId === undefined) { + option = $scope.newInterpreterSetting.option; + } else { + var index = _.findIndex($scope.interpreterSettings, {'id': settingId}); + var setting = $scope.interpreterSettings[index]; + option = setting.option; + } + + if (option.perUser === 'scoped') { return 'scoped'; - } else if (option.perNoteProcess) { + } else if (option.perUser === 'isolated') { return 'isolated'; } else { return 'shared'; } }; + $scope.getInterpreterRunningOption = function(settingId) { + var sharedModeName = 'shared'; + + var globallyModeName = 'Globally'; + var perNoteModeName = 'Per Note'; + var perUserModeName = 'Per User'; + + var option; + if (settingId === undefined) { + option = $scope.newInterpreterSetting.option; + } else { + var index = _.findIndex($scope.interpreterSettings, {'id': settingId}); + var setting = $scope.interpreterSettings[index]; + option = setting.option; + } + + var perNote = option.perNote; + var perUser = option.perUser; + + // Globally == shared_perNote + shared_perUser + if (perNote === sharedModeName && perUser === sharedModeName) { + return globallyModeName; + } + + if ($rootScope.ticket.ticket === 'anonymous' && $rootScope.ticket.roles === '[]') { + if (perNote !== undefined && typeof perNote === 'string' && perNote !== '') { + return perNoteModeName; + } + } else if ($rootScope.ticket.ticket !== 'anonymous') { + if (perNote !== undefined && typeof perNote === 'string' && perNote !== '') { + if (perUser !== undefined && typeof perUser === 'string' && perUser !== '') { + return perUserModeName; + } + return perNoteModeName; + } + } + + option.perNote = sharedModeName; + option.perUser = sharedModeName; + return globallyModeName; + }; + + $scope.setInterpreterRunningOption = function(settingId, isPerNoteMode, isPerUserMode) { + var option; + if (settingId === undefined) { + option = $scope.newInterpreterSetting.option; + } else { + var index = _.findIndex($scope.interpreterSettings, {'id': settingId}); + var setting = $scope.interpreterSettings[index]; + option = setting.option; + } + option.perNote = isPerNoteMode; + option.perUser = isPerUserMode; + }; + $scope.updateInterpreterSetting = function(form, settingId) { var thisConfirm = BootstrapDialog.confirm({ closable: false, @@ -402,8 +505,8 @@ remote: true, isExistingProcess: false, setPermission: false, - perNoteSession: false, - perNoteProcess: false + session: false, + process: false } }; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/908b2a74/zeppelin-web/src/app/interpreter/interpreter.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/interpreter/interpreter.html b/zeppelin-web/src/app/interpreter/interpreter.html index 57b305e..e0e8613 100644 --- a/zeppelin-web/src/app/interpreter/interpreter.html +++ b/zeppelin-web/src/app/interpreter/interpreter.html @@ -141,40 +141,172 @@ limitations under the License. </span> </div> </div> + <div class="row interpreter"> <div class="col-md-12"> <h5>Option</h5> - <span class="btn-group"> - <button type="button" class="btn btn-default btn-xs dropdown-toggle" - data-toggle="dropdown" - ng-disabled="!valueform.$visible"> - {{getSessionOption(setting.id)}} <span class="caret"></span> - </button> - <ul class="dropdown-menu" role="menu"> - <li> - <a style="cursor:pointer" - tooltip="Single interpreter instance are shared across notes" - ng-click="setSessionOption(setting.id, 'shared')"> - shared - </a> - </li> - <li> - <a style="cursor:pointer" - tooltip="Separate Interpreter instance for each note" - ng-click="setSessionOption(setting.id, 'scoped')"> - scoped - </a> - </li> - <li> - <a style="cursor:pointer" - tooltip="Separate Interpreter process for each note" - ng-click="setSessionOption(setting.id, 'isolated')"> - isolated - </a> - </li> - </ul> - </span> - <span>Interpreter for note</span> + <div class="row interpreter" style="margin-top: 5px;"> + <div class="col-md-6"> + The interpreter will be instantiated + <span class="btn-group"> + <button type="button" class="btn btn-default btn-xs dropdown-toggle" + data-toggle="dropdown" + ng-disabled="!valueform.$visible"> + {{getInterpreterRunningOption(setting.id)}} <span class="caret"></span> + </button> + <ul class="dropdown-menu" role="menu"> + <li> + <a style="cursor:pointer" + ng-click="setInterpreterRunningOption(setting.id, 'shared', 'shared')"> + Globally + </a> + </li> + <li> + <a style="cursor:pointer" + ng-click="setInterpreterRunningOption(setting.id, 'scoped', '')"> + Per Note + </a> + </li> + <li ng-if="ticket.ticket !== 'anonymous' && ticket.roles !== '[]'"> + <a style="cursor:pointer" + ng-click="setInterpreterRunningOption(setting.id, 'shared', 'scoped')"> + Per User + </a> + </li> + </ul> + </span> + in + <span class="btn-group"> + <button type="button" class="btn btn-default btn-xs dropdown-toggle" + data-toggle="dropdown" + ng-disabled="!valueform.$visible + || getInterpreterRunningOption(setting.id) === 'Globally'"> + <span ng-if="getInterpreterRunningOption(setting.id) !== 'Per User'"> + {{getPerNoteOption(setting.id)}} + </span> + <span ng-if="getInterpreterRunningOption(setting.id) === 'Per User'"> + {{getPerUserOption(setting.id)}} + </span> + <span class="caret"></span> + </button> + <ul class="dropdown-menu" role="menu"> + <li + ng-if="getInterpreterRunningOption(setting.id) === 'Globally'"> + <a style="cursor:pointer" + tooltip="Single interpreter instance are shared across notes" + ng-click="setPerNoteOption(setting.id, 'shared')"> + shared per note + </a> + </li> + + <li> + <a style="cursor:pointer" + ng-if="getInterpreterRunningOption(setting.id) === 'Per Note'" + tooltip="Separate Interpreter instance for each note" + ng-click="setPerNoteOption(setting.id, 'scoped')"> + scoped per note + </a> + </li> + <li> + <a style="cursor:pointer" + ng-if="getInterpreterRunningOption(setting.id) === 'Per User'" + tooltip="Separate Interpreter instance for each note" + ng-click="setPerUserOption(setting.id, 'scoped')"> + scoped per user + </a> + </li> + + <li> + <a style="cursor:pointer" + ng-if="getInterpreterRunningOption(setting.id) === 'Per Note'" + tooltip="Separate Interpreter process for each note" + ng-click="setPerNoteOption(setting.id, 'isolated')"> + isolated per note + </a> + </li> + <li> + <a style="cursor:pointer" + ng-if="getInterpreterRunningOption(setting.id) === 'Per User'" + tooltip="Separate Interpreter process for each note" + ng-click="setPerUserOption(setting.id, 'isolated')"> + isolated per user + </a> + </li> + </ul> + </span> + process. + <span ng-if="getInterpreterRunningOption(setting.id) === 'Per User' && ticket.ticket !== 'anonymous' && ticket.roles !== '[]'"> + <span ng-if="getPerNoteOption(setting.id) === 'shared'"> + <button type="button" class="btn btn-default btn-xs" + ng-click="setPerNoteOption(setting.id, 'scoped')" + ng-disabled="!valueform.$visible" + data-toggle="dropdown"> + <i class="fa fa-plus"></i> + </button> + </span> + </span> + </div> + <div class="col-md-6"> + + </div> + </div> + <div class="row interpreter" style="margin-top: 6px;"> + <div class="col-md-6"> + <span ng-if="getInterpreterRunningOption(setting.id) === 'Per User' && ticket.ticket !== 'anonymous' && ticket.roles !== '[]'"> + <span ng-if="getPerNoteOption(setting.id) !== 'shared'"> + <span class="hidden-xs" style="padding-left: 190px;">And </span> + <span class="visible-xs" style="padding-left: 0px;">And </span> + <span class="btn-group"> + <button type="button" class="btn btn-default btn-xs dropdown-toggle" + data-toggle="dropdown" + ng-disabled="true"> + <span> + Per Note + </span> + <span class="caret"></span> + </button> + </span> + in + <span class="btn-group"> + <button type="button" class="btn btn-default btn-xs dropdown-toggle" + data-toggle="dropdown" + ng-disabled="!valueform.$visible"> + <span> + {{getPerNoteOption(setting.id)}} + </span> + <span class="caret"></span> + </button> + <ul class="dropdown-menu" role="menu"> + <li> + <a style="cursor:pointer" + tooltip="Separate Interpreter instance for each note" + ng-click="setPerNoteOption(setting.id, 'scoped')"> + scoped per note + </a> + </li> + <li> + <a style="cursor:pointer" + tooltip="Separate Interpreter process for each note" + ng-click="setPerNoteOption(setting.id, 'isolated')"> + isolated per note + </a> + </li> + </ul> + </span> + process. + <button type="button" class="btn btn-default btn-xs" + ng-disabled="!valueform.$visible" + ng-click="setPerNoteOption(setting.id, 'shared')" + data-toggle="dropdown"> + <i class="fa fa-minus"></i> + </button> + </span> + </span> + </div> + <div class="col-md-6"> + + </div> + </div> </div> </div> <div class="row interpreter" style="margin-top: 5px;">
