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 b8d4d67 optionally limit cron fields to 5 instead of 6 (#126)
b8d4d67 is described below
commit b8d4d67abb015e728ea1db23c4b39e4b8674b45e
Author: Jason Peterson <[email protected]>
AuthorDate: Tue Feb 13 12:14:21 2018 -0500
optionally limit cron fields to 5 instead of 6 (#126)
---
action/alarmWebAction.js | 35 +++++-----
action/lib/common.js | 17 ++++-
installCatalog.sh | 37 +++++-----
.../system/health/AlarmsHealthFeedTests.scala | 78 +++-------------------
.../scala/system/packages/AlarmsFeedTests.scala | 31 ++++++++-
5 files changed, 92 insertions(+), 106 deletions(-)
diff --git a/action/alarmWebAction.js b/action/alarmWebAction.js
index d56a159..b5b5bde 100644
--- a/action/alarmWebAction.js
+++ b/action/alarmWebAction.js
@@ -72,6 +72,10 @@ function main(params) {
try {
cronHandle = new CronJob(params.cron, function() {});
+ //validate cron granularity if 5 fields are allowed
instead of 6
+ if (params.limitCronFields &&
hasSecondsGranularity(params.cron)) {
+ return common.sendError(400, 'cron pattern is limited
to 5 fields with 1 minute as the finest granularity');
+ }
newTrigger.cron = params.cron;
} catch(ex) {
return common.sendError(400, `cron pattern
'${params.cron}' is not valid`);
@@ -198,7 +202,7 @@ function main(params) {
}
if (params.trigger_payload) {
- updatedParams.payload =
constructPayload(params.trigger_payload);
+ updatedParams.payload =
common.constructPayload(params.trigger_payload);
}
if (trigger.date) {
@@ -228,6 +232,10 @@ function main(params) {
if (params.cron) {
try {
new CronJob(params.cron, function() {});
+ //validate cron granularity if 5 fields are
allowed instead of 6
+ if (params.limitCronFields &&
hasSecondsGranularity(params.cron)) {
+ return common.sendError(400, 'cron pattern
is limited to 5 fields with 1 minute as the finest granularity');
+ }
} catch (ex) {
return reject(common.sendError(400, `cron
pattern '${params.cron}' is not valid`));
}
@@ -313,20 +321,6 @@ function main(params) {
}
}
-function constructPayload(payload) {
-
- var updatedPayload;
- if (payload) {
- if (typeof payload === 'string') {
- updatedPayload = {payload: payload};
- }
- if (typeof payload === 'object') {
- updatedPayload = payload;
- }
- }
- return updatedPayload;
-}
-
function validateDate(date, paramName, startDate) {
var dateObject = new Date(date);
@@ -346,6 +340,17 @@ function validateDate(date, paramName, startDate) {
}
+function hasSecondsGranularity(cron) {
+
+ var fields = (cron + '').trim().split(/\s+/);
+
+ if (fields.length > 5 && fields[fields.length - 6] !== '0') {
+ return true;
+ }
+
+ return false;
+}
+
exports.main = main;
diff --git a/action/lib/common.js b/action/lib/common.js
index c62e1f8..663be12 100644
--- a/action/lib/common.js
+++ b/action/lib/common.js
@@ -104,11 +104,26 @@ function sendError(statusCode, error, message) {
};
}
+function constructPayload(payload) {
+
+ var updatedPayload;
+ if (payload) {
+ if (typeof payload === 'string') {
+ updatedPayload = {payload: payload};
+ }
+ if (typeof payload === 'object') {
+ updatedPayload = payload;
+ }
+ }
+ return updatedPayload;
+}
+
module.exports = {
'requestHelper': requestHelper,
'createWebParams': createWebParams,
'verifyTriggerAuth': verifyTriggerAuth,
'parseQName': parseQName,
- 'sendError': sendError
+ 'sendError': sendError,
+ 'constructPayload': constructPayload
};
diff --git a/installCatalog.sh b/installCatalog.sh
index ddc9337..85f6467 100755
--- a/installCatalog.sh
+++ b/installCatalog.sh
@@ -12,9 +12,8 @@ set -x
: ${OPENWHISK_HOME:?"OPENWHISK_HOME must be set and non-empty"}
WSK_CLI="$OPENWHISK_HOME/bin/wsk"
-if [ $# -eq 0 ]
-then
-echo "Usage: ./installCatalog.sh <authkey> <edgehost> <dburl> <dbprefix>
<apihost> <workers>"
+if [ $# -eq 0 ]; then
+ echo "Usage: ./installCatalog.sh <authkey> <edgehost> <dburl> <dbprefix>
<apihost> <workers>"
fi
AUTH="$1"
@@ -23,6 +22,7 @@ DB_URL="$3"
DB_NAME="${4}alarmservice"
APIHOST="$5"
WORKERS="$6"
+LIMIT_CRON_FIELDS="${LIMIT_CRON_FIELDS}"
# If the auth key file exists, read the key in the file. Otherwise, take the
# first argument as the key itself.
@@ -57,8 +57,7 @@ $WSK_CLI -i --apihost "$EDGEHOST" package update --auth
"$AUTH" --shared yes ala
# make alarmFeed.zip
cd action
-if [ -e alarmFeed.zip ]
-then
+if [ -e alarmFeed.zip ]; then
rm -rf alarmFeed.zip
fi
@@ -82,26 +81,26 @@ $WSK_CLI -i --apihost "$EDGEHOST" action update --kind
nodejs:6 --auth "$AUTH" a
-a feed true \
-p isInterval true
-if [ -n "$WORKERS" ];
-then
- $WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared
no alarmsWeb \
- -p DB_URL "$DB_URL" \
- -p DB_NAME "$DB_NAME" \
- -p apihost "$APIHOST" \
- -p workers "$WORKERS"
-else
- $WSK_CLI -i --apihost "$EDGEHOST" package update --auth "$AUTH" --shared
no alarmsWeb \
- -p DB_URL "$DB_URL" \
- -p DB_NAME "$DB_NAME" \
- -p apihost "$APIHOST"
+COMMAND=" -i --apihost $EDGEHOST package update --auth $AUTH --shared no
alarmsWeb \
+ -p DB_URL $DB_URL \
+ -p DB_NAME $DB_NAME \
+ -p apihost $APIHOST"
+
+if [ -n "$WORKERS" ]; then
+ COMMAND+=" -p workers $WORKERS"
+fi
+
+if [ -n "$LIMIT_CRON_FIELDS" ]; then
+ COMMAND+=" -p limitCronFields $LIMIT_CRON_FIELDS"
fi
+$WSK_CLI $COMMAND
+
# make alarmWebAction.zip
cp -f alarmWeb_package.json package.json
npm install
-if [ -e alarmWebAction.zip ];
-then
+if [ -e alarmWebAction.zip ]; then
rm -rf alarmWebAction.zip
fi
diff --git a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
index cbee2c5..e1b84f4 100644
--- a/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
+++ b/tests/src/test/scala/system/health/AlarmsHealthFeedTests.scala
@@ -43,67 +43,6 @@ class AlarmsHealthFeedTests
behavior of "Alarms Health tests"
- it should "bind alarm package and fire periodic trigger using cron feed"
in withAssetCleaner(wskprops) {
- (wp, assetHelper) =>
- implicit val wskprops = wp // shadow global props and make implicit
- val triggerName = s"dummyAlarmsTrigger-${System.currentTimeMillis}"
- val ruleName = s"dummyAlarmsRule-${System.currentTimeMillis}"
- val actionName = s"dummyAlarmsAction-${System.currentTimeMillis}"
- val packageName = "dummyAlarmsPackage"
-
- // the package alarms should be there
- val packageGetResult = wsk.pkg.get("/whisk.system/alarms")
- println("fetched package alarms")
- packageGetResult.stdout should include("ok")
-
- // create package binding
- assetHelper.withCleaner(wsk.pkg, packageName) {
- (pkg, name) => pkg.bind("/whisk.system/alarms", name)
- }
-
- // create action
- assetHelper.withCleaner(wsk.action, actionName) { (action, name) =>
- action.create(name, defaultAction)
- }
-
- // create trigger feed
- println(s"Creating trigger: $triggerName")
- assetHelper.withCleaner(wsk.trigger, triggerName) {
- (trigger, name) =>
- trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
- "trigger_payload" -> "alarmTest".toJson,
- "cron" -> "* * * * * *".toJson))
- }
-
- // create rule
- assetHelper.withCleaner(wsk.rule, ruleName) { (rule, name) =>
- rule.create(name, trigger = triggerName, action = actionName)
- }
-
- println("waiting for triggers")
- val activations = wsk.activation.pollFor(N = 5, Some(triggerName),
retries = 30).length
- println(s"Found activation size (should be at least 5):
$activations")
- activations should be >= 5
-
- // delete the whisk trigger, which must also delete the feed
- wsk.trigger.delete(triggerName)
-
- // get activation list after delete of the trigger
- val activationsAfterDelete = wsk.activation.pollFor(N = 100,
Some(triggerName), retries = 30).length
- val now = Instant.now(Clock.systemUTC())
- println(s"Found activation size after delete ($now):
$activationsAfterDelete")
-
- // recreate the trigger now without the feed
- wsk.trigger.create(triggerName)
-
- // get activation list again, should be same as before waiting
- println("confirming no new triggers")
- val activationsAfterWait = wsk.activation.pollFor(N =
activationsAfterDelete + 1, Some(triggerName)).length
- println(s"Found activation size after wait: $activationsAfterWait")
- println("Activation list after wait should equal with activation
list after delete")
- activationsAfterWait should be(activationsAfterDelete)
- }
-
it should "fire an alarm once trigger when specifying a future date" in
withAssetCleaner(wskprops) {
(wp, assetHelper) =>
implicit val wskprops = wp // shadow global props and make implicit
@@ -173,14 +112,14 @@ class AlarmsHealthFeedTests
}
val startDate = System.currentTimeMillis + (1000 * 20)
- val stopDate = startDate + (1000 * 10)
+ val stopDate = startDate + (1000 * 60)
// create trigger feed
println(s"Creating trigger: $triggerName")
assetHelper.withCleaner(wsk.trigger, triggerName) {
(trigger, name) =>
trigger.create(name, feed = Some(s"$packageName/alarm"),
parameters = Map(
- "cron" -> "* * * * * *".toJson,
+ "cron" -> "* * * * *".toJson,
"startDate" -> startDate.toJson,
"stopDate" -> stopDate.toJson))
}
@@ -191,9 +130,9 @@ class AlarmsHealthFeedTests
}
println("waiting for triggers")
- val activations = wsk.activation.pollFor(N = 20,
Some(triggerName), retries = 60).length
- println(s"Found activation size (should be at least 5):
$activations")
- activations should be >= 5
+ val activations = wsk.activation.pollFor(N = 1, Some(triggerName),
retries = 90).length
+ println(s"Found activation size (should be 1): $activations")
+ activations should be(1)
// get activation list again, should be same as before waiting
@@ -277,8 +216,7 @@ class AlarmsHealthFeedTests
val triggerPayload = JsObject(
"test" -> JsString("alarmsTest")
)
- val cronString = "* * * * * *"
- val maxTriggers = -1
+ val cronString = "* * * * *"
// create trigger feed
val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName) {
@@ -335,7 +273,7 @@ class AlarmsHealthFeedTests
(pkg, name) => pkg.bind("/whisk.system/alarms", name)
}
- val cron = "* * * * * *"
+ val cron = "* * * * *"
val startDate = System.currentTimeMillis + (1000 * 20)
val stopDate = startDate + (1000 * 10)
@@ -371,7 +309,7 @@ class AlarmsHealthFeedTests
}
}
- val updatedCron = "*/2 * * * * *"
+ val updatedCron = "*/2 * * * *"
val updatedStartDate = System.currentTimeMillis + (1000 * 20)
val updatedStopDate = updatedStartDate + (1000 * 10)
diff --git a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
index 62dd74f..59c4b0a 100644
--- a/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
+++ b/tests/src/test/scala/system/packages/AlarmsFeedTests.scala
@@ -20,7 +20,7 @@ import common._
import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.junit.JUnitRunner
-import spray.json.DefaultJsonProtocol.{IntJsonFormat, LongJsonFormat,
StringJsonFormat}
+import spray.json.DefaultJsonProtocol.{BooleanJsonFormat, IntJsonFormat,
LongJsonFormat, StringJsonFormat}
import spray.json.{JsString, pimpAny}
/**
@@ -452,4 +452,33 @@ class AlarmsFeedTests
error.fields("error") shouldBe JsString(s"startDate
parameter '${updatedStartDate}' must be less than the stopDate parameter
'${stopDate}'")
}
}
+
+ it should "return error message when limitCronFields is true and 6 cron
fields are used" in withAssetCleaner(wskprops) {
+ (wp, assetHelper) =>
+ implicit val wskprops = wp // shadow global props and make implicit
+ val triggerName =
s"dummyCloudantTrigger-${System.currentTimeMillis}"
+ val packageName = "dummyCloudantPackage"
+ val feed = "alarm"
+
+ // the package alarms should be there
+ val packageGetResult = wsk.pkg.get("/whisk.system/alarms")
+ println("fetched package alarms")
+ packageGetResult.stdout should include("ok")
+
+ // create package binding
+ assetHelper.withCleaner(wsk.pkg, packageName) {
+ (pkg, name) => pkg.bind("/whisk.system/alarms", name)
+ }
+
+ // create trigger with feed
+ val feedCreationResult = assetHelper.withCleaner(wsk.trigger,
triggerName, confirmDelete = false) {
+ (trigger, name) =>
+ trigger.create(name, feed = Some(s"$packageName/$feed"),
parameters = Map(
+ "cron" -> "* * * * * *".toJson,
+ "limitCronFields" -> true.toJson),
+ expectedExitCode = 246)
+ }
+ feedCreationResult.stderr should include("cron pattern is limited
to 5 fields with 1 minute as the finest granularity")
+
+ }
}
--
To stop receiving notification emails like this one, please contact
[email protected].