Repository: zeppelin Updated Branches: refs/heads/master 821b61bb6 -> 79fd3a024
[ZEPPELIN-1376] Add proxy credentials for dependency repo for corporate firewall use-cases ### What is this PR for? When using Zeppelin behind corporate firewall, sometimes the dependencies download just fails silently. This PR has 2 objectives: * add proxy credentials information for dependencies repo * raise clear error message in case of dependencies download failure There are 3 commits. The first one add extra inputs in the form for adding new repository  The second commit fixes some issues and display a clear and explicit error message when download of dependencies fail. Before that, when the download fails, we can see the below behaviour  * the error message is displayed twice because the call twice the method `checkDownloadingDependencies();`. One in the success callback of: ```javascript $scope.updateInterpreterSetting = function(form, settingId) { ... $http.put(baseUrlSrv.getRestApiBase() + '/interpreter/setting/' + settingId, request) .success(function(data, status, headers, config) { $scope.interpreterSettings[index] = data.body; removeTMPSettings(index); thisConfirm.close(); checkDownloadingDependencies(); $route.reload(); }) .error(function(data, status, headers, config) { ... }; ``` Another call is inside success callback of `getInterpreterSettings()` ```javascript var getInterpreterSettings = function() { $http.get(baseUrlSrv.getRestApiBase() + '/interpreter/setting') .success(function(data, status, headers, config) { $scope.interpreterSettings = data.body; checkDownloadingDependencies(); }).error(function(data, status, headers, config) { .... ``` The problem is that `$route.reload();` in the success callback of `updateInterpreterSetting()` will trigger `init()` then `getInterpreterSettings()` so `checkDownloadingDependencies()` is called twice. I remove the call to `checkDownloadingDependencies()` from success callback of `updateInterpreterSetting()` The second modification is on class `DependencyResolver`. In the screen capture above, we get a **cryptic** NullPointerException coming from `DefaultRepositorySystem`. I now catch this NPE to wrap it into a more sensible and clearer exception: ```java public List<ArtifactResult> getArtifactsWithDep(String dependency, Collection<String> excludes) throws RepositoryException { Artifact artifact = new DefaultArtifact(dependency); DependencyFilter classpathFilter = DependencyFilterUtils.classpathFilter(JavaScopes.COMPILE); PatternExclusionsDependencyFilter exclusionFilter = new PatternExclusionsDependencyFilter(excludes); CollectRequest collectRequest = new CollectRequest(); collectRequest.setRoot(new Dependency(artifact, JavaScopes.COMPILE)); synchronized (repos) { for (RemoteRepository repo : repos) { collectRequest.addRepository(repo); } } DependencyRequest dependencyRequest = new DependencyRequest(collectRequest, DependencyFilterUtils.andFilter(exclusionFilter, classpathFilter)); //Catch NPE thrown by aether and give a proper error message try { return system.resolveDependencies(session, dependencyRequest).getArtifactResults(); } catch (NullPointerException ex) { throw new RepositoryException(String.format("Cannot fetch dependencies for %s", dependency)); } } ``` The result is much more cleaner  The last commit is just doc update  ### What type of PR is it? [Improvement] ### Todos * [ ] - Code Review * [ ] - Simple test with no Internet connection * [ ] - Test within a corporate firewall env with a third-party dependency, requiring download ### What is the Jira issue? **[ZEPPELIN-1376]** ### How should this be tested? ##### Simple test * `git fetch origin pull/1369/head:WebProxy` * `git checkout WebProxy` * `mvn clean package -DskipTests` * `bin/zeppelin-daemon.sh restart` * disconnect from the Internet (pull out the cable, shutdown wifi ...) * add a random dependency to the Spark interpreter (take `info.archinnov:achilles-core:4.2.2` for example) * validate the change, you should see an error popup on the top-right corner saying that Zeppelin cannot download the dependency ##### Corporate firewall test * follow the steps above for simple test * create a new repository (see how to **[here]**) and set the proxy information * retry the steps above to ensure that the download is successful ### Screenshots (if appropriate) See above ### Questions: * Does the licenses files need update? --> **NO** * Is there breaking changes for older versions? --> **NO** * Does this needs documentation? --> **YES, DONE** [ZEPPELIN-1376]: https://issues.apache.org/jira/browse/ZEPPELIN-1376 [here]: http://localhost:4000/manual/dependencymanagement.html Author: DuyHai DOAN <[email protected]> Author: doanduyhai <[email protected]> Closes #1369 from doanduyhai/ZEPPELIN-1376 and squashes the following commits: b8d44e7 [doanduyhai] [ZEPPELIN-1376] Improve error popup display 177fbd3 [DuyHai DOAN] [ZEPPELIN-1376] Fixes JS bug to display error popup for other interpreters 9f76ef4 [DuyHai DOAN] [ZEPPELIN-1376] Do not repeat the same error popup multiple times b264193 [DuyHai DOAN] [ZEPPELIN-1376] Add unit test and fix impl for DependencyResolver to catch NPE 1913a0a [DuyHai DOAN] [ZEPPELIN-1376] Update documentation f01be9b [DuyHai DOAN] [ZEPPELIN-1376] Raise clear error message in case of dependencies download failure 6f2b6f8 [DuyHai DOAN] [ZEPPELIN-1376] Add proxy credentials information for dependencies repo Project: http://git-wip-us.apache.org/repos/asf/zeppelin/repo Commit: http://git-wip-us.apache.org/repos/asf/zeppelin/commit/79fd3a02 Tree: http://git-wip-us.apache.org/repos/asf/zeppelin/tree/79fd3a02 Diff: http://git-wip-us.apache.org/repos/asf/zeppelin/diff/79fd3a02 Branch: refs/heads/master Commit: 79fd3a0242df9f7324410cfc5d987850ee3de405 Parents: 821b61b Author: DuyHai DOAN <[email protected]> Authored: Sat Oct 1 22:24:21 2016 +0200 Committer: doanduyhai <[email protected]> Committed: Mon Oct 10 09:27:30 2016 +0200 ---------------------------------------------------------------------- .../img/docs-img/interpreter-add-repo2.png | Bin 359948 -> 88167 bytes docs/manual/dependencymanagement.md | 1 + .../dep/AbstractDependencyResolver.java | 3 +- .../apache/zeppelin/dep/DependencyResolver.java | 14 +++++-- .../org/apache/zeppelin/dep/Repository.java | 21 ++++++++++ .../zeppelin/dep/DependencyResolverTest.java | 13 +++++++ .../zeppelin/rest/InterpreterRestApi.java | 7 +--- zeppelin-web/src/app/app.js | 1 + .../configuration/configuration.controller.js | 1 + .../src/app/credential/credential.controller.js | 1 + zeppelin-web/src/app/home/home.controller.js | 6 ++- .../app/interpreter/interpreter.controller.js | 22 ++++++++--- .../src/app/interpreter/interpreter.html | 4 +- .../src/app/jobmanager/jobmanager.controller.js | 5 ++- .../src/app/notebook/notebook.controller.js | 9 ++++- .../repository-create/repository-dialog.html | 38 +++++++++++++++++++ .../interpreter/InterpreterFactory.java | 13 ++++--- 17 files changed, 132 insertions(+), 27 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/docs/assets/themes/zeppelin/img/docs-img/interpreter-add-repo2.png ---------------------------------------------------------------------- diff --git a/docs/assets/themes/zeppelin/img/docs-img/interpreter-add-repo2.png b/docs/assets/themes/zeppelin/img/docs-img/interpreter-add-repo2.png index bc7c2eb..62708c6 100644 Binary files a/docs/assets/themes/zeppelin/img/docs-img/interpreter-add-repo2.png and b/docs/assets/themes/zeppelin/img/docs-img/interpreter-add-repo2.png differ http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/docs/manual/dependencymanagement.md ---------------------------------------------------------------------- diff --git a/docs/manual/dependencymanagement.md b/docs/manual/dependencymanagement.md index dc478c4..44068da 100644 --- a/docs/manual/dependencymanagement.md +++ b/docs/manual/dependencymanagement.md @@ -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> http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/AbstractDependencyResolver.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/AbstractDependencyResolver.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/AbstractDependencyResolver.java index 1e0844e..da3d0c0 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/AbstractDependencyResolver.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/AbstractDependencyResolver.java @@ -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); } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/DependencyResolver.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/DependencyResolver.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/DependencyResolver.java index 87d9178..7ca4a4d 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/DependencyResolver.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/DependencyResolver.java @@ -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)); + } } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/Repository.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/Repository.java b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/Repository.java index d2b0092..34fe4f0 100644 --- a/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/Repository.java +++ b/zeppelin-interpreter/src/main/java/org/apache/zeppelin/dep/Repository.java @@ -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; + } } http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-interpreter/src/test/java/org/apache/zeppelin/dep/DependencyResolverTest.java ---------------------------------------------------------------------- diff --git a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/dep/DependencyResolverTest.java b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/dep/DependencyResolverTest.java index af2c7ff..876e8e7 100644 --- a/zeppelin-interpreter/src/test/java/org/apache/zeppelin/dep/DependencyResolverTest.java +++ b/zeppelin-interpreter/src/test/java/org/apache/zeppelin/dep/DependencyResolverTest.java @@ -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); + } + } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java ---------------------------------------------------------------------- diff --git a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java index 6025b52..5b1773b 100644 --- a/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java +++ b/zeppelin-server/src/main/java/org/apache/zeppelin/rest/InterpreterRestApi.java @@ -35,7 +35,6 @@ import com.google.gson.Gson; import org.apache.commons.lang.exception.ExceptionUtils; 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; @@ -73,9 +72,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(); } /** @@ -202,7 +199,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); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/app/app.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/app.js b/zeppelin-web/src/app/app.js index f0f1d89..603171f 100644 --- a/zeppelin-web/src/app/app.js +++ b/zeppelin-web/src/app/app.js @@ -90,6 +90,7 @@ ngToastProvider.configure({ dismissButton: true, dismissOnClick: false, + combineDuplications: true, timeout: 6000 }); }); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/app/configuration/configuration.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/configuration/configuration.controller.js b/zeppelin-web/src/app/configuration/configuration.controller.js index 611575e..8960ca5 100644 --- a/zeppelin-web/src/app/configuration/configuration.controller.js +++ b/zeppelin-web/src/app/configuration/configuration.controller.js @@ -21,6 +21,7 @@ function ConfigurationCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) { $scope.configrations = []; $scope._ = _; + ngToast.dismiss(); var getConfigurations = function() { $http.get(baseUrlSrv.getRestApiBase() + '/configurations/all'). http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/app/credential/credential.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/credential/credential.controller.js b/zeppelin-web/src/app/credential/credential.controller.js index bfb8bba..7145299 100644 --- a/zeppelin-web/src/app/credential/credential.controller.js +++ b/zeppelin-web/src/app/credential/credential.controller.js @@ -20,6 +20,7 @@ function CredentialCtrl($scope, $rootScope, $http, baseUrlSrv, ngToast) { $scope._ = _; + ngToast.dismiss(); $scope.credentialInfo = []; $scope.showAddNewCredentialInfo = false; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/app/home/home.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/home/home.controller.js b/zeppelin-web/src/app/home/home.controller.js index 2c7407b..9063e33 100644 --- a/zeppelin-web/src/app/home/home.controller.js +++ b/zeppelin-web/src/app/home/home.controller.js @@ -21,10 +21,12 @@ 'notebookListDataFactory', 'websocketMsgSrv', '$rootScope', - 'arrayOrderingSrv' + 'arrayOrderingSrv', + 'ngToast' ]; - function HomeCtrl($scope, notebookListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv) { + function HomeCtrl($scope, notebookListDataFactory, websocketMsgSrv, $rootScope, arrayOrderingSrv, ngToast) { + ngToast.dismiss(); var vm = this; vm.notes = notebookListDataFactory; vm.websocketMsgSrv = websocketMsgSrv; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/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 97d4ea7..3fe355f 100644 --- a/zeppelin-web/src/app/interpreter/interpreter.controller.js +++ b/zeppelin-web/src/app/interpreter/interpreter.controller.js @@ -25,6 +25,7 @@ $scope.showAddNewSetting = false; $scope.showRepositoryInfo = false; $scope._ = _; + ngToast.dismiss(); $scope.openPermissions = function() { $scope.showInterpreterAuth = true; @@ -108,12 +109,19 @@ 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') { @@ -236,7 +244,6 @@ $scope.interpreterSettings[index] = data.body; removeTMPSettings(index); thisConfirm.close(); - checkDownloadingDependencies(); $route.reload(); }) .error(function(data, status, headers, config) { @@ -508,7 +515,12 @@ url: '', snapshot: false, username: '', - password: '' + password: '', + proxyProtocol: 'HTTP', + proxyHost: '', + proxyPort: null, + proxyLogin: '', + proxyPassword: '' }; }; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/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 f1c5e65..57b305e 100644 --- a/zeppelin-web/src/app/interpreter/interpreter.html +++ b/zeppelin-web/src/app/interpreter/interpreter.html @@ -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}} <span ng-if="!isDefaultRepository(repo.id)" class="fa fa-close blackOpc" http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/app/jobmanager/jobmanager.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/jobmanager/jobmanager.controller.js b/zeppelin-web/src/app/jobmanager/jobmanager.controller.js index 2c6b675..d28b374 100644 --- a/zeppelin-web/src/app/jobmanager/jobmanager.controller.js +++ b/zeppelin-web/src/app/jobmanager/jobmanager.controller.js @@ -16,9 +16,10 @@ angular.module('zeppelinWebApp').controller('JobmanagerCtrl', JobmanagerCtrl); - JobmanagerCtrl.$inject = ['$scope', 'websocketMsgSrv', '$interval']; + JobmanagerCtrl.$inject = ['$scope', 'websocketMsgSrv', '$interval', 'ngToast']; - function JobmanagerCtrl($scope, websocketMsgSrv, $interval) { + function JobmanagerCtrl($scope, websocketMsgSrv, $interval, ngToast) { + ngToast.dismiss(); $scope.filterValueToName = function(filterValue) { var index = _.findIndex($scope.ACTIVE_INTERPRETERS, {value: filterValue}); http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/app/notebook/notebook.controller.js ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/app/notebook/notebook.controller.js b/zeppelin-web/src/app/notebook/notebook.controller.js index da15768..f2aa67d 100644 --- a/zeppelin-web/src/app/notebook/notebook.controller.js +++ b/zeppelin-web/src/app/notebook/notebook.controller.js @@ -26,11 +26,16 @@ 'websocketMsgSrv', 'baseUrlSrv', '$timeout', - 'saveAsService' + 'saveAsService', + 'ngToast' ]; function NotebookCtrl($scope, $route, $routeParams, $location, $rootScope, - $http, websocketMsgSrv, baseUrlSrv, $timeout, saveAsService) { + $http, websocketMsgSrv, baseUrlSrv, $timeout, saveAsService, + ngToast) { + + ngToast.dismiss(); + $scope.note = null; $scope.moment = moment; $scope.editorToggled = false; http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-web/src/components/repository-create/repository-dialog.html ---------------------------------------------------------------------- diff --git a/zeppelin-web/src/components/repository-create/repository-dialog.html b/zeppelin-web/src/components/repository-create/repository-dialog.html index d2efec3..ab678b7 100644 --- a/zeppelin-web/src/components/repository-create/repository-dialog.html +++ b/zeppelin-web/src/components/repository-create/repository-dialog.html @@ -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" http://git-wip-us.apache.org/repos/asf/zeppelin/blob/79fd3a02/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java ---------------------------------------------------------------------- diff --git a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java index 58adb48..494361b 100644 --- a/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java +++ b/zeppelin-zengine/src/main/java/org/apache/zeppelin/interpreter/InterpreterFactory.java @@ -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 { @@ -1307,9 +1310,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(); }
