csantanapr closed pull request #126: optionally limit cron fields to 5 instead of 6 URL: https://github.com/apache/incubator-openwhisk-package-alarms/pull/126
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/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") + + } } ---------------------------------------------------------------- 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