csantanapr closed pull request #128: Allow delete of trigger and rules after 
firing alarms once action
URL: https://github.com/apache/incubator-openwhisk-package-alarms/pull/128
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

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) =>


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


With regards,
Apache Git Services

Reply via email to