Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZEPPELIN-885 Add option to send email in scheduler execution #918

Closed
wants to merge 6 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions conf/zeppelin-site.xml.template
Original file line number Diff line number Diff line change
@@ -289,4 +289,59 @@
<description>Size in characters of the maximum text message to be received by websocket. Defaults to 1024000</description>
</property>

<!--
<property>
<name>zeppelin.mail.smtp.user</name>
<value>email</value>
<description>SMTP user</description>
</property>

<property>
<name>zeppelin.mail.smtp.password</name>
<value>password</value>
<description>Password for SMTP user</description>
</property>

<property>
<name>zeppelin.mail.smtp.host</name>
<value>smtp.googlemail.com</value>
<description>The SMTP server to connect to.</description>
</property>

<property>
<name>zeppelin.mail.smtp.protocol</name>
<value>smtp</value>
<description>SMTP protocol</description>
</property>

<property>
<name>zeppelin.mail.smtp.port</name>
<value>465</value>
<description>The SMTP server port to connect</description>
</property>

<property>
<name>zeppelin.mail.smtp.starttls.enable</name>
<value>true</value>
<description>If true, enables the use of the STARTTLS command (if supported by the server) to switch the connection to a TLS-protected connection before issuing any login commands.</description>
</property>

<property>
<name>zeppelin.mail.smtp.auth</name>
<value>true</value>
<description>If true, attempt to authenticate the user using the AUTH command.</description>
</property>

<property>
<name>zeppelin.mail.smtp.socketFactory.port</name>
<value>465</value>
<description>Specifies the port to connect to when using the specified socket factory.</description>
</property>

<property>
<name>zeppelin.mail.smtp.socketFactory.class</name>
<value>javax.net.ssl.SSLSocketFactory</value>
<description>Specifies the name of a class that implements the javax.net.SocketFactory interface. This class will be used to create SMTP sockets.</description>
</property>
-->
</configuration>
54 changes: 54 additions & 0 deletions docs/install/install.md
Original file line number Diff line number Diff line change
@@ -336,6 +336,60 @@ You can configure Apache Zeppelin with either **environment variables** in `conf
<td>1024000</td>
<td>Size (in characters) of the maximum text message that can be received by websocket.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_USER</td>
<td>zeppelin.mail.smtp.user</td>
<td></td>
<td>SMTP user.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_PASS</td>
<td>zeppelin.mail.smtp.password</td>
<td></td>
<td>Password for SMTP user.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_HOST</td>
<td>zeppelin.mail.smtp.host</td>
<td>smtp.googlemail.com</td>
<td>The SMTP server to connect to.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_PROTOCOL</td>
<td>zeppelin.mail.smtp.protocol</td>
<td>smtp</td>
<td>SMTP protocol.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_PORT</td>
<td>zeppelin.mail.smtp.port</td>
<td>465</td>
<td>The SMTP server port to connect.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_STARTTLSZEPPELIN_SMTP_AUTH</td>
<td>zeppelin.mail.smtp.starttls.enable</td>
<td>true</td>
<td>If true, enables the use of the STARTTLS command (if supported by the server) to switch the connection to a TLS-protected connection before issuing any login commands.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_AUTH</td>
<td>zeppelin.mail.smtp.auth</td>
<td>true</td>
<td>If true, attempt to authenticate the user using the AUTH command.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_SOCKETFACTORY</td>
<td>zeppelin.mail.smtp.socketFactory.port</td>
<td>465</td>
<td>Specifies the port to connect to when using the specified socket factory.</td>
</tr>
<tr>
<td>ZEPPELIN_SMTP_SOCKETFACTORY_CLASS</td>
<td>zeppelin.mail.smtp.socketFactory.class</td>
<td>javax.net.ssl.SSLSocketFactory</td>
<td>Specifies the name of a class that implements the javax.net.SocketFactory interface. This class will be used to create SMTP sockets.</td>
</tr>
</table>


Original file line number Diff line number Diff line change
@@ -68,6 +68,10 @@ public boolean isRunning() {
public boolean isPending() {
return this == PENDING;
}

public boolean isError() {
return this == ERROR;
}
}

private String jobName;
45 changes: 4 additions & 41 deletions zeppelin-web/src/app/notebook/notebook-actionBar.html
Original file line number Diff line number Diff line change
@@ -11,6 +11,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<div ng-include id="scheduler-modal-container" src="'components/scheduler/scheduler-dialog.html'"></div>
<div class="noteAction" ng-show="note.id && !paragraphUrl">
<h3>
<div style="float: left; width: auto; max-width: 40%"
@@ -123,7 +124,7 @@ <h3>
</ul>
</div>
</span>

</div>
<!-- put the delete action by itself for your protection -->
<span class="labelBtn" style="vertical-align:middle; display:inline-block;">
<button type="button"
@@ -139,52 +140,14 @@ <h3>
<div class="labelBtn btn-group">
<div class="btn btn-default btn-xs dropdown-toggle"
type="button"
data-toggle="dropdown"
data-toggle="modal"
data-target="#schedulerModal"
ng-class="{ 'btn-info' : note.config.cron, 'btn-danger' : note.info.cron, 'btn-default' : !note.config.cron}"
tooltip-placement="bottom" tooltip="Run scheduler">
<span class="fa fa-clock-o"></span> {{getCronOptionNameFromValue(note.config.cron)}}
</div>
<ul class="dropdown-menu" role="menu" style="width:300px">
<li>
<div class="cron-preset-container">
Run note with cron scheduler.
Either choose from preset or write your own <a href="http://www.quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/crontrigger" target="_blank">cron expression</a>.
<div>
<span>- Preset</span>
<a class="cron-preset" ng-repeat="cr in cronOption"
type="button"
ng-click="setCronScheduler(cr.value)"
dropdown-input ng-class="{ 'selected' : cr.value == note.config.cron}">{{cr.name}}</a>
</div>
<div>
<span>- Cron expression</span>
<input type="text"
ng-model="note.config.cron"
ng-change="setCronScheduler(note.config.cron)"
dropdown-input ng-model-options="{ debounce: 1000 }" />
<p ng-show="note.info.cron" class="text-danger cron-info">
{{note.info.cron}}
</p>
</div>
<div>
<span>- Cron executing user (click enter in field to submit)</span>
<input type="text"
ng-model="note.config.cronExecutingUser"
ng-enter="setCronExecutingUser(note.config.cronExecutingUser)"
dropdown-input />
</div>
<div>
<span>- auto-restart interpreter on cron execution </span>
<input type="checkbox"
ng-model="note.config.releaseresource"
ng-click="setReleaseResource(note.config.releaseresource)"/>
</div>
</div>
</li>
</ul>
</div>
</span>
</div>

<div class="pull-right" style="margin-top:15px; margin-right:15px; margin-left: 15px; margin-bottom: 13px; font-size:15px;">
<span class="setting-btn"
9 changes: 7 additions & 2 deletions zeppelin-web/src/app/notebook/notebook.controller.js
Original file line number Diff line number Diff line change
@@ -38,6 +38,7 @@
ngToast.dismiss();

$scope.note = null;
$scope.config = {};
$scope.moment = moment;
$scope.editorToggled = false;
$scope.tableToggled = false;
@@ -296,10 +297,13 @@
$scope.setConfig();
};

$scope.reset = function() {
$scope.note.config = angular.copy($scope.config);
};

/** Set cron expression for this note **/
$scope.setCronScheduler = function(cronExpr) {
$scope.note.config.cron = cronExpr;
$scope.setConfig();
};

/** Set the username of the user to be used to execute all notes in notebook **/
@@ -311,11 +315,11 @@
/** Set release resource for this note **/
$scope.setReleaseResource = function(value) {
$scope.note.config.releaseresource = value;
$scope.setConfig();
};

/** Update note config **/
$scope.setConfig = function(config) {
console.log(config);
if (config) {
$scope.note.config = config;
}
@@ -824,6 +828,7 @@
initializeLookAndFeel();
//open interpreter binding setting when there're none selected
getInterpreterBindings();
$scope.config = angular.copy($scope.note.config);
});

$scope.$on('$destroy', function() {
107 changes: 107 additions & 0 deletions zeppelin-web/src/components/scheduler/scheduler-dialog.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<div id="schedulerModal" class="modal fade" role="dialog" tabindex='-1'>
<div class="modal-dialog">

<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">&times;</button>
<h4 class="modal-title">Scheduler note</h4>
</div>
<form class="form-horizontal">
<div class="modal-body">

<div>
<!-- Nav tabs -->
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#scheduler" aria-controls="scheduler" role="tab" data-toggle="tab">Scheduler</a></li>
<li role="presentation"><a href="#alert" aria-controls="alert" role="tab" data-toggle="tab">Notification</a></li>
</ul>

<!-- Tab panes -->
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="scheduler">
<p>
Run note with cron scheduler.
Either choose from preset or write your own <a href="http://www.quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger" target=_blank>cron expression</a>.
</p>
<div>
<label>- Preset</label>
<a class="cron-preset" ng-repeat="cr in cronOption"
type="button"
ng-click="setCronScheduler(cr.value)"
dropdown-input ng-class="{ 'selected' : cr.value == note.config.cron}">{{cr.name}}</a>
</div>
<div>
<label>- Cron expression</label>
<input type="text"
ng-model="note.config.cron"
dropdown-input ng-model-options="{ debounce: 1000 }" />
<p ng-show="note.info.cron" class="text-danger cron-info">
{{note.info.cron}}
</p>
</div>
<div>
<label>- Cron executing user (click enter in field to submit)</label>
<input type="text"
ng-model="note.config.cronExecutingUser"
ng-enter="setCronExecutingUser(note.config.cronExecutingUser)"
dropdown-input />
</div>
<div>
<label>- auto-restart interpreter on cron execution </label>
<input type="checkbox"
ng-model="note.config.releaseresource"
ng-click="setReleaseResource(note.config.releaseresource)" />
</div>

</div>
<div role="tabpanel" class="tab-pane" id="alert">
<p>
Enter a addresses to email when a run starts, success, or encounters an error.
</p>
<div class="form-group">
<label class="control-label col-sm-3">On start</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="startEmail" ng-model="note.config.notification.email.start"
placeholder="Emails (comma-separated)" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3">On success</label>
<div class="col-sm-8">
<input type="text"class="form-control" id="successEmail" ng-model="note.config.notification.email.finish"
placeholder="Emails (comma-separated)">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-3">On error</label>
<div class="col-sm-8">
<input type="text"class="form-control" id="errorEmail" ng-model="note.config.notification.email.error"
placeholder="Emails (comma-separated)">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" ng-click="setConfig(note.config)" data-dismiss="modal">Ok
</button>
<button type="button" class="btn btn-default" ng-click="reset()" data-dismiss="modal">Cancel
</button>
</div>
</form>
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions zeppelin-zengine/pom.xml
Original file line number Diff line number Diff line change
@@ -97,6 +97,18 @@
<artifactId>commons-vfs2</artifactId>
<version>2.0</version>
</dependency>

<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.4</version>
<exclusions>
<exclusion>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>org.apache.jackrabbit</groupId>
Original file line number Diff line number Diff line change
@@ -591,7 +591,17 @@ public static enum ConfVars {
ZEPPELIN_ALLOWED_ORIGINS("zeppelin.server.allowed.origins", "*"),
ZEPPELIN_ANONYMOUS_ALLOWED("zeppelin.anonymous.allowed", true),
ZEPPELIN_CREDENTIALS_PERSIST("zeppelin.credentials.persist", true),
ZEPPELIN_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE("zeppelin.websocket.max.text.message.size", "1024000");
ZEPPELIN_WEBSOCKET_MAX_TEXT_MESSAGE_SIZE("zeppelin.websocket.max.text.message.size", "1024000"),
ZEPPELIN_SMTP_USER("zeppelin.mail.smtp.user", "mail"),
ZEPPELIN_SMTP_PASS("zeppelin.mail.smtp.password", "passwod"),
ZEPPELIN_SMTP_HOST("zeppelin.mail.smtp.host", "smtp.googlemail.com"),
ZEPPELIN_SMTP_PROTOCOL("zeppelin.mail.smtp.protocol", "smtp"),
ZEPPELIN_SMTP_PORT("zeppelin.mail.smtp.port", "465"),
ZEPPELIN_SMTP_STARTTLS("zeppelin.mail.smtp.starttls.enable", "true"),
ZEPPELIN_SMTP_AUTH("zeppelin.mail.smtp.auth", "true"),
ZEPPELIN_SMTP_SOCKETFACTORY("zeppelin.mail.smtp.socketFactory.port", "465"),
ZEPPELIN_SMTP_SOCKETFACTORY_CLASS("zeppelin.mail.smtp.socketFactory.class",
"javax.net.ssl.SSLSocketFactory");

private String varName;
@SuppressWarnings("rawtypes")
Loading