You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by cs...@apache.org on 2018/02/19 15:48:12 UTC
[incubator-openwhisk-package-alarms] branch master updated: Allow
delete of trigger and rules after firing alarms once action (#128)
This is an automated email from the ASF dual-hosted git repository.
csantanapr pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk-package-alarms.git
The following commit(s) were added to refs/heads/master by this push:
new 13ccc29 Allow delete of trigger and rules after firing alarms once action (#128)
13ccc29 is described below
commit 13ccc29a119f80dfea8ae824b793fceb295d02c3
Author: Jason Peterson <ja...@us.ibm.com>
AuthorDate: Mon Feb 19 10:48:10 2018 -0500
Allow delete of trigger and rules after firing alarms once action (#128)
---
README.md | 36 +++---
action/alarmWebAction.js | 23 +++-
action/lib/Database.js | 15 ++-
gradle/docker.gradle | 16 ++-
installCatalog.sh | 2 +-
provider/lib/cronAlarm.js | 4 +-
provider/lib/dateAlarm.js | 5 +-
provider/lib/intervalAlarm.js | 4 +-
provider/lib/sanitizer.js | 143 +++++++++++++++++++++
provider/lib/utils.js | 84 +++++++-----
settings.gradle | 2 +-
.../system/health/AlarmsHealthFeedTests.scala | 79 ++++++------
12 files changed, 307 insertions(+), 106 deletions(-)
diff --git a/README.md b/README.md
index 53c88aa..466feaf 100644
--- a/README.md
+++ b/README.md
@@ -11,7 +11,7 @@ The package includes the following feeds.
| --- | --- | --- | --- |
| `/whisk.system/alarms` | package | - | Alarms and periodic utility. |
| `/whisk.system/alarms/interval` | feed | minutes, trigger_payload, startDate, stopDate | Fire Trigger event on an interval based schedule. |
-| `/whisk.system/alarms/once` | feed | date, trigger_payload | Fire Trigger event once on a specific date. |
+| `/whisk.system/alarms/once` | feed | date, trigger_payload, deleteAfterFire | Fire Trigger event once on a specific date. |
| `/whisk.system/alarms/alarm` | feed | cron, trigger_payload, startDate, stopDate | Fire Trigger event on a time-based schedule using cron. |
@@ -19,17 +19,17 @@ The package includes the following feeds.
The `/whisk.system/alarms/interval` feed configures the Alarm service to fire a Trigger event on an interval based schedule. The parameters are as follows:
-- `minutes`: An integer representing the length of the interval (in minutes) between trigger fires.
+- `minutes` (*required*): An integer representing the length of the interval (in minutes) between trigger fires.
-- `trigger_payload`: The value of this parameter becomes the content of the Trigger every time the Trigger is fired.
+- `trigger_payload` (*optional*): The value of this parameter becomes the content of the Trigger every time the Trigger is fired.
-- `startDate`: The date when the first trigger will be fired. Subsequent fires will occur based on the interval length specified by the `minutes` parameter.
+- `startDate` (*optional*): The date when the first trigger will be fired. Subsequent fires will occur based on the interval length specified by the `minutes` parameter.
-- `stopDate`: The date when the trigger will stop running. Triggers will no longer be fired once this date has been reached.
+- `stopDate` (*optional*): The date when the Trigger will stop running. Triggers will no longer be fired once this date has been reached.
**Note**: The `startDate` and `stopDate` parameters support an integer or string value. The integer value represents the number of milliseconds since 1 January 1970 00:00:00 UTC and the string value should be in the ISO 8601 format (http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15).
-The following example creates a trigger that is fired once every 2 minutes. The trigger fires as soon as possible, and will stop firing January 31, 2019, 23:59:00 UTC.
+The following example creates a trigger that is fired once every 2 minutes. The Trigger fires as soon as possible, and will stop firing January 31, 2019, 23:59:00 UTC.
```
wsk trigger create interval \
@@ -45,27 +45,33 @@ Each generated event includes parameters, which are the properties that are spec
The `/whisk.system/alarms/once` feed configures the Alarm service to fire a trigger event on a specified date. The parameters are as follows:
-- `date`: The date when the trigger will be fired. The trigger will be fired just once at the given time.
+- `date` (*required*): The date when the Trigger will be fired. The Trigger will be fired just once at the given time.
**Note**: The `date` parameter supports an integer or string value. The integer value represents the number of milliseconds
since 1 January 1970 00:00:00 UTC and the string value should be in the ISO 8601 format (http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15).
-- `trigger_payload`: The value of this parameter becomes the content of the Trigger when the Trigger is fired.
+- `trigger_payload` (*optional*): The value of this parameter becomes the content of the Trigger when the Trigger is fired.
-The following is an example of creating a trigger that will be fired once on December 25, 2017, 12:30:00 UTC.
+- `deleteAfterFire` (*optional*, default: false): The value of this parameter determines whether the Trigger and potentially all of its associated rules will be deleted after the Trigger is fired.
+ - `false`: No action will be taken after the Trigger fires.
+ - `true`: The Trigger will be deleted after it fires.
+ - `rules`: The Trigger and all of its associated rules will be deleted after it fires.
+
+The following is an example of creating a trigger that will be fired once on December 25, 2019, 12:30:00 UTC. After the Trigger fires it will be deleted as well as all of its associated rules.
```
wsk trigger create fireOnce \
--feed /whisk.system/alarms/once \
--param trigger_payload "{\"name\":\"Odin\",\"place\":\"Asgard\"}" \
- --param date "2017-12-25T12:30:00.000Z"
+ --param date "2019-12-25T12:30:00.000Z" \
+ --param deleteAfterFire "rules"
```
## Firing a Trigger on a time-based schedule using cron
The `/whisk.system/alarms/alarm` feed configures the Alarm service to fire a Trigger event at a specified frequency. The parameters are as follows:
-- `cron`: A string, based on the UNIX crontab syntax that indicates when to fire the Trigger in Coordinated Universal Time (UTC). The string is a sequence of five fields that are separated by spaces: `X X X X X`.
+- `cron` (*required*): A string, based on the UNIX crontab syntax that indicates when to fire the Trigger in Coordinated Universal Time (UTC). The string is a sequence of five fields that are separated by spaces: `X X X X X`.
For more information, see: http://crontab.org. The following strings are examples that use varying duration's of frequency.
- `* * * * *`: The Trigger fires at the top of every minute.
@@ -78,15 +84,15 @@ For more information, see: http://crontab.org. The following strings are example
Here is an example using six fields notation:
- `*/30 * * * * *`: every thirty seconds.
-- `trigger_payload`: The value of this parameter becomes the content of the Trigger every time the Trigger is fired.
+- `trigger_payload` (*optional*): The value of this parameter becomes the content of the Trigger every time the Trigger is fired.
-- `startDate`: The date when the Trigger will start running. The Trigger fires based on the schedule specified by the cron parameter.
+- `startDate` (*optional*): The date when the Trigger will start running. The Trigger fires based on the schedule specified by the cron parameter.
-- `stopDate`: The date when the Trigger will stop running. Triggers are no longer fired once this date is reached.
+- `stopDate` (*optional*): The date when the Trigger will stop running. Triggers are no longer fired once this date is reached.
**Note**: The `startDate` and `stopDate` parameters support an integer or string value. The integer value represents the number of milliseconds since 1 January 1970 00:00:00 UTC, and the string value should be in the ISO 8601 format (http://www.ecma-international.org/ecma-262/5.1/#sec-15.9.1.15).
-The following is an example of creating a trigger that fires once every 2 minutes with `name` and `place` values in the trigger event. The trigger will not start firing until
+The following is an example of creating a trigger that fires once every 2 minutes with `name` and `place` values in the trigger event. The Trigger will not start firing until
January 1, 2019, 00:00:00 UTC and will stop firing January 31, 2019, 23:59:00 UTC.
```
diff --git a/action/alarmWebAction.js b/action/alarmWebAction.js
index b5b5bde..478af06 100644
--- a/action/alarmWebAction.js
+++ b/action/alarmWebAction.js
@@ -18,6 +18,7 @@ function main(params) {
var triggerURL = `https://${params.apihost}/api/v1/namespaces/${triggerParts.namespace}/triggers/${triggerParts.name}`;
var workers = params.workers instanceof Array ? params.workers : [];
+ var deleteAfterFireArray = ['false', 'true', 'rules'];
var db;
if (params.__ow_method === "post") {
@@ -47,6 +48,14 @@ function main(params) {
return common.sendError(400, date);
}
newTrigger.date = date;
+
+ if (params.deleteAfterFire) {
+ var deleteAfterFire = ('' + params.deleteAfterFire).trim().toLowerCase();
+ if (deleteAfterFireArray.indexOf(deleteAfterFire) === -1) {
+ return common.sendError(400, 'deleteAfterFire parameter must be one of [false, true, rules].');
+ }
+ newTrigger.deleteAfterFire = deleteAfterFire;
+ }
}
else {
var cronHandle;
@@ -213,6 +222,14 @@ function main(params) {
}
updatedParams.date = date;
}
+
+ if (params.deleteAfterFire) {
+ var deleteAfterFire = ('' + params.deleteAfterFire).trim().toLowerCase();
+ if (deleteAfterFireArray.indexOf(deleteAfterFire) === -1) {
+ return common.sendError(400, 'deleteAfterFire parameter must be one of [false, true, rules].');
+ }
+ newTrigger.deleteAfterFire = deleteAfterFire;
+ }
}
else {
if (trigger.minutes) {
@@ -344,11 +361,7 @@ function hasSecondsGranularity(cron) {
var fields = (cron + '').trim().split(/\s+/);
- if (fields.length > 5 && fields[fields.length - 6] !== '0') {
- return true;
- }
-
- return false;
+ return fields.length > 5 && fields[fields.length - 6] !== '0';
}
exports.main = main;
diff --git a/action/lib/Database.js b/action/lib/Database.js
index fcf062b..236f2f5 100644
--- a/action/lib/Database.js
+++ b/action/lib/Database.js
@@ -63,12 +63,12 @@ module.exports = function(dbURL, dbName) {
return new Promise(function(resolve, reject) {
- utilsDB.db.get(triggerID, function (err, existing) {
+ var qName = triggerID.split('/');
+ var id = retry ? triggerID : qName[0] + '/_/' + qName[2];
+ utilsDB.db.get(id, function (err, existing) {
if (err) {
if (retry) {
- var parts = triggerID.split('/');
- var id = parts[0] + '/_/' + parts[2];
- utilsDB.getTrigger(id, false)
+ utilsDB.getTrigger(triggerID, false)
.then(doc => {
resolve(doc);
})
@@ -76,7 +76,8 @@ module.exports = function(dbURL, dbName) {
reject(err);
});
} else {
- reject(common.sendError(err.statusCode, 'could not find the trigger in the database'));
+ var name = '/' + qName[1] + '/' + qName[2];
+ reject(common.sendError(err.statusCode, 'could not find trigger ' + name + ' in the database'));
}
} else {
resolve(existing);
@@ -156,7 +157,9 @@ module.exports = function(dbURL, dbName) {
});
}
else {
- reject(common.sendError(err.statusCode, 'could not find the trigger in the database'));
+ var qName = triggerID.split('/');
+ var name = '/' + qName[1] + '/' + qName[2];
+ reject(common.sendError(err.statusCode, 'could not find trigger ' + name + ' in the database'));
}
});
});
diff --git a/gradle/docker.gradle b/gradle/docker.gradle
index 8192d3a..c74ba30 100644
--- a/gradle/docker.gradle
+++ b/gradle/docker.gradle
@@ -37,16 +37,21 @@ if(project.hasProperty('dockerHost')) {
}
if(project.hasProperty('dockerBuildArgs')) {
- dockerBuildArg += ['--build-arg', project.dockerBuildArgs]
+ dockerBuildArgs.each { arg ->
+ dockerBuildArg += ['--build-arg', arg]
+ }
}
-task distDocker << {
+task distDocker {
+ doLast {
def start = new Date()
def cmd = dockerBinary + dockerBuildArg + ['-t', dockerImageName, project.buildscript.sourceFile.getParentFile().getAbsolutePath()]
retry(cmd, dockerRetries, dockerTimeout)
println("Building '${dockerImageName}' took ${TimeCategory.minus(new Date(), start)}")
}
-task tagImage << {
+}
+task tagImage {
+ doLast {
def versionString = (dockerBinary + ['-v']).execute().text
def matched = (versionString =~ /(\d+)\.(\d+)\.(\d+)/)
@@ -59,11 +64,14 @@ task tagImage << {
}
retry(dockerBinary + dockerCmd + [dockerImageName, dockerTaggedImageName], dockerRetries, dockerTimeout)
}
+}
-task pushImage << {
+task pushImage {
+ doLast {
def cmd = dockerBinary + ['push', dockerTaggedImageName]
retry(cmd, dockerRetries, dockerTimeout)
}
+}
pushImage.dependsOn tagImage
pushImage.onlyIf { dockerRegistry != '' }
distDocker.finalizedBy pushImage
diff --git a/installCatalog.sh b/installCatalog.sh
index 85f6467..9261716 100755
--- a/installCatalog.sh
+++ b/installCatalog.sh
@@ -71,7 +71,7 @@ $WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" a
$WSK_CLI -i --apihost "$EDGEHOST" action update --kind nodejs:6 --auth "$AUTH" alarms/once "$PACKAGE_HOME/action/alarmFeed.zip" \
-a description 'Fire trigger once when alarm occurs' \
- -a parameters '[ {"name":"date", "required":true} ]' \
+ -a parameters '[ {"name":"date", "required":true}, {"name":"deleteAfterFire", "required":false} ]' \
-a feed true \
-p fireOnce true
diff --git a/provider/lib/cronAlarm.js b/provider/lib/cronAlarm.js
index f60ec62..ff89d39 100644
--- a/provider/lib/cronAlarm.js
+++ b/provider/lib/cronAlarm.js
@@ -11,7 +11,9 @@ module.exports = function(logger, newTrigger) {
name: newTrigger.name,
namespace: newTrigger.namespace,
payload: newTrigger.payload,
- cron: newTrigger.cron
+ cron: newTrigger.cron,
+ triggerID: newTrigger.triggerID,
+ uri: newTrigger.uri
};
this.scheduleAlarm = function(triggerIdentifier, callback) {
diff --git a/provider/lib/dateAlarm.js b/provider/lib/dateAlarm.js
index 011261d..f505ca2 100644
--- a/provider/lib/dateAlarm.js
+++ b/provider/lib/dateAlarm.js
@@ -7,7 +7,10 @@ module.exports = function(logger, newTrigger) {
name: newTrigger.name,
namespace: newTrigger.namespace,
payload: newTrigger.payload,
- date: newTrigger.date
+ date: newTrigger.date,
+ deleteAfterFire: newTrigger.deleteAfterFire,
+ triggerID: newTrigger.triggerID,
+ uri: newTrigger.uri
};
this.scheduleAlarm = function(triggerIdentifier, callback) {
diff --git a/provider/lib/intervalAlarm.js b/provider/lib/intervalAlarm.js
index 077a68b..39d1a78 100644
--- a/provider/lib/intervalAlarm.js
+++ b/provider/lib/intervalAlarm.js
@@ -8,7 +8,9 @@ module.exports = function(logger, newTrigger) {
name: newTrigger.name,
namespace: newTrigger.namespace,
payload: newTrigger.payload,
- minutes: newTrigger.minutes
+ minutes: newTrigger.minutes,
+ triggerID: newTrigger.triggerID,
+ uri: newTrigger.uri
};
this.scheduleAlarm = function(triggerIdentifier, callback) {
diff --git a/provider/lib/sanitizer.js b/provider/lib/sanitizer.js
new file mode 100644
index 0000000..19bb747
--- /dev/null
+++ b/provider/lib/sanitizer.js
@@ -0,0 +1,143 @@
+var request = require('request');
+
+module.exports = function(logger, triggerDB, uriHost) {
+
+ var sanitizer = this;
+
+ this.deleteTriggerFromDB = function(triggerID, retryCount) {
+ var method = 'deleteTriggerFromDB';
+
+ //delete from database
+ triggerDB.get(triggerID, function (err, existing) {
+ if (!err) {
+ triggerDB.destroy(existing._id, existing._rev, function (err) {
+ if (err) {
+ if (err.statusCode === 409 && retryCount < 5) {
+ setTimeout(function () {
+ sanitizer.deleteTriggerFromDB(triggerID, (retryCount + 1));
+ }, 1000);
+ }
+ else {
+ logger.error(method, triggerID, 'there was an error deleting the trigger from the database');
+ }
+ }
+ });
+ }
+ else {
+ logger.error(method, triggerID, 'could not find the trigger in the database');
+ }
+ });
+ };
+
+ this.deleteTriggerAndRules = function(dataTrigger) {
+ var method = 'deleteTriggerAndRules';
+
+ var triggerIdentifier = dataTrigger.triggerID;
+ var auth = dataTrigger.apikey.split(':');
+
+ request({
+ method: 'get',
+ uri: dataTrigger.uri,
+ auth: {
+ user: auth[0],
+ pass: auth[1]
+ },
+ }, function(error, response, body) {
+ logger.info(method, triggerIdentifier, 'http get request, STATUS:', response ? response.statusCode : undefined);
+
+ if (error || response.statusCode >= 400) {
+ logger.error(method, triggerIdentifier, 'trigger get request failed');
+ }
+ else {
+ //delete the trigger
+ sanitizer.deleteTrigger(dataTrigger, auth, 0)
+ .then((info) => {
+ logger.info(method, triggerIdentifier, info);
+ if (body) {
+ try {
+ var jsonBody = JSON.parse(body);
+ for (var rule in jsonBody.rules) {
+ var qualifiedName = rule.split('/');
+ var uri = uriHost + '/api/v1/namespaces/' + qualifiedName[0] + '/rules/' + qualifiedName[1];
+ sanitizer.deleteRule(rule, uri, auth, 0);
+ }
+ }
+ catch (err) {
+ logger.error(method, triggerIdentifier, err);
+ }
+ }
+ })
+ .catch(err => {
+ logger.error(method, triggerIdentifier, err);
+ });
+ }
+ });
+ };
+
+ this.deleteTrigger = function(dataTrigger, auth, retryCount) {
+ var method = 'deleteTrigger';
+
+ return new Promise(function(resolve, reject) {
+
+ var triggerIdentifier = dataTrigger.triggerID;
+ request({
+ method: 'delete',
+ uri: dataTrigger.uri,
+ auth: {
+ user: auth[0],
+ pass: auth[1]
+ },
+ }, function (error, response) {
+ logger.info(method, triggerIdentifier, 'http delete request, STATUS:', response ? response.statusCode : undefined);
+ if (error || response.statusCode >= 400) {
+ if (!error && response.statusCode === 409 && retryCount < 5) {
+ logger.info(method, 'attempting to delete trigger again', triggerIdentifier, 'Retry Count:', (retryCount + 1));
+ setTimeout(function () {
+ sanitizer.deleteTrigger(dataTrigger, auth, (retryCount + 1))
+ .then(info => {
+ resolve(info);
+ })
+ .catch(err => {
+ reject(err);
+ });
+ }, 1000);
+ } else {
+ reject('trigger delete request failed');
+ }
+ }
+ else {
+ resolve('trigger delete request was successful');
+ }
+ });
+ });
+ };
+
+ this.deleteRule = function(rule, uri, auth, retryCount) {
+ var method = 'deleteRule';
+
+ request({
+ method: 'delete',
+ uri: uri,
+ auth: {
+ user: auth[0],
+ pass: auth[1]
+ },
+ }, function(error, response) {
+ logger.info(method, rule, 'http delete rule request, STATUS:', response ? response.statusCode : undefined);
+ if (error || response.statusCode >= 400) {
+ if (!error && response.statusCode === 409 && retryCount < 5) {
+ logger.info(method, 'attempting to delete rule again', rule, 'Retry Count:', (retryCount + 1));
+ setTimeout(function () {
+ sanitizer.deleteRule(rule, uri, auth, (retryCount + 1));
+ }, 1000);
+ } else {
+ logger.error(method, rule, 'rule delete request failed');
+ }
+ }
+ else {
+ logger.info(method, rule, 'rule delete request was successful');
+ }
+ });
+ };
+
+};
diff --git a/provider/lib/utils.js b/provider/lib/utils.js
index a8f3153..6402b85 100644
--- a/provider/lib/utils.js
+++ b/provider/lib/utils.js
@@ -5,12 +5,10 @@ var constants = require('./constants.js');
var DateAlarm = require('./dateAlarm.js');
var CronAlarm = require('./cronAlarm.js');
var IntervalAlarm = require('./intervalAlarm.js');
+var Sanitizer = require('./sanitizer');
+
+module.exports = function(logger, triggerDB, redisClient) {
-module.exports = function(
- logger,
- triggerDB,
- redisClient
-) {
this.module = 'utils';
this.triggers = {};
this.endpointAuth = process.env.ENDPOINT_AUTH;
@@ -22,6 +20,8 @@ module.exports = function(
this.redisClient = redisClient;
this.redisHash = triggerDB.config.db + '_' + this.worker;
this.redisKey = constants.REDIS_KEY;
+ this.uriHost ='https://' + this.routerHost + ':443';
+ this.sanitizer = new Sanitizer(logger, triggerDB, this.uriHost);
var retryDelay = constants.RETRY_DELAY;
var retryAttempts = constants.RETRY_ATTEMPTS;
@@ -46,6 +46,9 @@ module.exports = function(
}
};
+ newTrigger.uri = utils.uriHost + '/api/v1/namespaces/' + newTrigger.namespace + '/triggers/' + newTrigger.name;
+ newTrigger.triggerID = triggerIdentifier;
+
var alarm;
if (newTrigger.date) {
alarm = new DateAlarm(logger, newTrigger);
@@ -63,24 +66,22 @@ module.exports = function(
this.fireTrigger = function(dataTrigger) {
var method = 'fireTrigger';
- var triggerIdentifier = utils.getTriggerIdentifier(dataTrigger.apikey, dataTrigger.namespace, dataTrigger.name);
- var host = 'https://' + utils.routerHost + ':443';
+ var triggerIdentifier = dataTrigger.triggerID;
var auth = dataTrigger.apikey.split(':');
- var uri = host + '/api/v1/namespaces/' + dataTrigger.namespace + '/triggers/' + dataTrigger.name;
logger.info(method, 'Alarm fired for', triggerIdentifier, 'attempting to fire trigger');
- utils.postTrigger(dataTrigger, uri, auth, 0)
+ utils.postTrigger(dataTrigger, auth, 0)
.then(triggerId => {
logger.info(method, 'Trigger', triggerId, 'was successfully fired');
- utils.disableExtinctTriggers(triggerIdentifier, dataTrigger);
+ utils.handleExpiredTriggers(dataTrigger);
})
.catch(err => {
logger.error(method, err);
- utils.disableExtinctTriggers(triggerIdentifier, dataTrigger);
+ utils.handleExpiredTriggers(dataTrigger);
});
};
- this.postTrigger = function(dataTrigger, uri, auth, retryCount) {
+ this.postTrigger = function(dataTrigger, auth, retryCount) {
var method = 'postTrigger';
return new Promise(function(resolve, reject) {
@@ -92,7 +93,7 @@ module.exports = function(
request({
method: 'post',
- uri: uri,
+ uri: dataTrigger.uri,
auth: {
user: auth[0],
pass: auth[1]
@@ -100,8 +101,8 @@ module.exports = function(
json: dataTrigger.payload
}, function(error, response) {
try {
- var triggerIdentifier = utils.getTriggerIdentifier(dataTrigger.apikey, dataTrigger.namespace, dataTrigger.name);
- logger.info(method, triggerIdentifier, 'http post request, STATUS:', response ? response.statusCode : response);
+ var triggerIdentifier = dataTrigger.triggerID;
+ logger.info(method, triggerIdentifier, 'http post request, STATUS:', response ? response.statusCode : undefined);
if (error || response.statusCode >= 400) {
// only manage trigger fires if they are not infinite
@@ -119,7 +120,7 @@ module.exports = function(
if (retryCount < retryAttempts) {
logger.info(method, 'attempting to fire trigger again', triggerIdentifier, 'Retry Count:', (retryCount + 1));
setTimeout(function () {
- utils.postTrigger(dataTrigger, uri, auth, (retryCount + 1))
+ utils.postTrigger(dataTrigger, auth, (retryCount + 1))
.then(triggerId => {
resolve(triggerId);
})
@@ -148,12 +149,36 @@ module.exports = function(
[HttpStatus.REQUEST_TIMEOUT, HttpStatus.TOO_MANY_REQUESTS].indexOf(statusCode) === -1);
};
- this.disableExtinctTriggers = function(triggerIdentifier, dataTrigger) {
- var method = 'disableExtinctTriggers';
+ this.handleExpiredTriggers = function(dataTrigger) {
+ var method = 'handleExpiredTriggers';
+ var triggerIdentifier = dataTrigger.triggerID;
if (dataTrigger.date) {
- utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after firing once');
- logger.info(method, 'the fire once date has expired, disabled', triggerIdentifier);
+ if (dataTrigger.deleteAfterFire && dataTrigger.deleteAfterFire !== 'false') {
+ utils.stopTrigger(triggerIdentifier);
+
+ //delete trigger feed from database
+ utils.sanitizer.deleteTriggerFromDB(triggerIdentifier, 0);
+
+ //check if trigger and all associated rules should be deleted
+ if (dataTrigger.deleteAfterFire === 'rules') {
+ utils.sanitizer.deleteTriggerAndRules(dataTrigger);
+ }
+ else {
+ var auth = dataTrigger.apikey.split(':');
+ utils.sanitizer.deleteTrigger(dataTrigger, auth, 0)
+ .then((info) => {
+ logger.info(method, triggerIdentifier, info);
+ })
+ .catch(err => {
+ logger.error(method, triggerIdentifier, err);
+ });
+ }
+ }
+ else {
+ utils.disableTrigger(triggerIdentifier, undefined, 'Automatically disabled after firing once');
+ logger.info(method, 'the fire once date has expired, disabled', triggerIdentifier);
+ }
}
else if (dataTrigger.stopDate) {
//check if the next scheduled trigger is after the stop date
@@ -199,14 +224,14 @@ module.exports = function(
}
else {
logger.info(method, 'could not find', triggerIdentifier, 'in database');
- //make sure it is removed from memory as well
- utils.deleteTrigger(triggerIdentifier);
+ //make sure it is already stopped
+ utils.stopTrigger(triggerIdentifier);
}
});
};
- this.deleteTrigger = function(triggerIdentifier) {
- var method = 'deleteTrigger';
+ this.stopTrigger = function (triggerIdentifier) {
+ var method = 'stopTrigger';
if (utils.triggers[triggerIdentifier]) {
if (utils.triggers[triggerIdentifier].cronHandle) {
@@ -220,10 +245,6 @@ module.exports = function(
}
};
- this.getTriggerIdentifier = function(apikey, namespace, name) {
- return apikey + '/' + namespace + '/' + name;
- };
-
this.initAllTriggers = function() {
var method = 'initAllTriggers';
@@ -242,14 +263,13 @@ module.exports = function(
var namespace = doc.namespace;
var name = doc.name;
var apikey = doc.apikey;
- var host = 'https://' + utils.routerHost + ':' + 443;
- var triggerURL = host + '/api/v1/namespaces/' + namespace + '/triggers/' + name;
+ var uri = utils.uriHost + '/api/v1/namespaces/' + namespace + '/triggers/' + name;
var auth = apikey.split(':');
logger.info(method, 'Checking if trigger', triggerIdentifier, 'still exists');
request({
method: 'get',
- url: triggerURL,
+ url: uri,
auth: {
user: auth[0],
pass: auth[1]
@@ -308,7 +328,7 @@ module.exports = function(
if (utils.triggers[triggerIdentifier]) {
if (doc.status && doc.status.active === false) {
- utils.deleteTrigger(triggerIdentifier);
+ utils.stopTrigger(triggerIdentifier);
}
}
else {
diff --git a/settings.gradle b/settings.gradle
index 9c7a819..33ecef8 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -11,6 +11,6 @@ include 'tests'
rootProject.name = 'openwhisk-package-alarms'
gradle.ext.scala = [
- version: '2.11.8',
+ version: '2.11.11',
compileFlags: ['-feature', '-unchecked', '-deprecation', '-Xfatal-warnings', '-Ywarn-unused-import']
]
diff --git a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
index 456d9ab..e158f7a 100644
--- a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
@@ -35,9 +35,8 @@ class AlarmsHealthFeedTests
val wskprops = WskProps()
val wsk = new Wsk
-
-
val defaultAction = Some(TestUtils.getTestActionFilename("hello.js"))
+ val maxRetries = System.getProperty("max.retries", "100").toInt
behavior of "Alarms Health tests"
@@ -60,8 +59,8 @@ class AlarmsHealthFeedTests
}
//create action
- assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
- action.create(name, defaultAction)
+ assetHelper.withCleaner(wsk.action, actionName) {
+ (action, name) => action.create(name, defaultAction)
}
val futureDate = System.currentTimeMillis + (1000 * 20)
@@ -72,18 +71,30 @@ class AlarmsHealthFeedTests
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/once"), parameters = Map(
"trigger_payload" -> "alarmTest".toJson,
- "date" -> futureDate.toJson))
+ "date" -> futureDate.toJson,
+ "deleteAfterFire" -> "rules".toJson))
}
// create rule
- assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action = actionName)
+ assetHelper.withCleaner(wsk.rule, ruleName) {
+ (rule, name) => rule.create(name, trigger = triggerName, action = actionName)
}
println("waiting for trigger")
- val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = 90).length
+ val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = maxRetries).length
println(s"Found activation size (should be 1): $activations")
activations should be(1)
+
+ // get activation list again, should be same as before waiting
+ println("confirming no new triggers")
+ val afterWait = wsk.activation.pollFor(N = activations + 1, Some(triggerName)).length
+ println(s"Found activation size after wait: $afterWait")
+ println("Activation list after wait should equal with activation list after firing once")
+ afterWait should be(activations)
+
+ //check that assets had been deleted by verifying we can recreate them
+ wsk.trigger.create(triggerName)
+ wsk.rule.create(ruleName, triggerName, actionName)
}
it should "fire cron trigger using startDate and stopDate" in withAssetCleaner(wskprops) {
@@ -105,8 +116,8 @@ class AlarmsHealthFeedTests
}
// create action
- assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
- action.create(name, defaultAction)
+ assetHelper.withCleaner(wsk.action, actionName) {
+ (action, name) => action.create(name, defaultAction)
}
val startDate = System.currentTimeMillis + (1000 * 20)
@@ -123,12 +134,12 @@ class AlarmsHealthFeedTests
}
// create rule
- assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action = actionName)
+ assetHelper.withCleaner(wsk.rule, ruleName) {
+ (rule, name) => rule.create(name, trigger = triggerName, action = actionName)
}
println("waiting for triggers")
- val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = 90).length
+ val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = maxRetries).length
println(s"Found activation size (should be 1): $activations")
activations should be(1)
@@ -160,8 +171,8 @@ class AlarmsHealthFeedTests
}
// create action
- assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
- action.create(name, defaultAction)
+ assetHelper.withCleaner(wsk.action, actionName) {
+ (action, name) => action.create(name, defaultAction)
}
val startDate = System.currentTimeMillis + (1000 * 20)
@@ -178,17 +189,17 @@ class AlarmsHealthFeedTests
}
// create rule
- assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action = actionName)
+ assetHelper.withCleaner(wsk.rule, ruleName) {
+ (rule, name) => rule.create(name, trigger = triggerName, action = actionName)
}
println("waiting for start date")
- val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = 90).length
+ val activations = wsk.activation.pollFor(N = 1, Some(triggerName), retries = maxRetries).length
println(s"Found activation size (should be 1): $activations")
activations should be(1)
println("waiting for interval")
- val activationsAfterInterval = wsk.activation.pollFor(N = 2, Some(triggerName), retries = 90).length
+ val activationsAfterInterval = wsk.activation.pollFor(N = 2, Some(triggerName), retries = maxRetries).length
println(s"Found activation size (should be 2): $activationsAfterInterval")
activationsAfterInterval should be(2)
}
@@ -233,8 +244,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, run) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside (activation.response.result) {
case Some(result) =>
@@ -294,8 +304,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, readRunResult) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside(activation.response.result) {
case Some(result) =>
@@ -321,8 +330,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, updateRunAction) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
}
val runResult = wsk.action.invoke(actionName, parameters = Map(
@@ -332,8 +340,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, runResult) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside(activation.response.result) {
case Some(result) =>
@@ -384,8 +391,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, readRunResult) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside(activation.response.result) {
case Some(result) =>
@@ -410,8 +416,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, updateRunAction) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
}
val runResult = wsk.action.invoke(actionName, parameters = Map(
@@ -421,8 +426,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, runResult) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside(activation.response.result) {
case Some(result) =>
@@ -473,8 +477,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, readRunResult) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside(activation.response.result) {
case Some(result) =>
@@ -500,8 +503,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, updateRunAction) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
}
val runResult = wsk.action.invoke(actionName, parameters = Map(
@@ -511,8 +513,7 @@ class AlarmsHealthFeedTests
))
withActivation(wsk.activation, runResult) {
- activation =>
- activation.response.success shouldBe true
+ activation => activation.response.success shouldBe true
inside(activation.response.result) {
case Some(result) =>
--
To stop receiving notification emails like this one, please contact
csantanapr@apache.org.