You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by dg...@apache.org on 2018/07/09 20:01:14 UTC
[incubator-openwhisk] branch master updated: Add action limits to
API host standard response (#3859)
This is an automated email from the ASF dual-hosted git repository.
dgrove pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-openwhisk.git
The following commit(s) were added to refs/heads/master by this push:
new acbef6a Add action limits to API host standard response (#3859)
acbef6a is described below
commit acbef6aa714f65b29c5fe67b68c7fd2ffbce159a
Author: rodric rabbah <ro...@gmail.com>
AuthorDate: Mon Jul 9 16:01:10 2018 -0400
Add action limits to API host standard response (#3859)
Adds the min_action* and sequence_length to the limits property accessible from the API host.
Adjusts a test which needs the sequence limit to use this information.
Co-authored-by: David Grove <gr...@us.ibm.com>
Co-authored-by: Markus Thömmes <ma...@me.com>
---
.../main/scala/whisk/core/entity/LogLimit.scala | 8 ++++----
.../main/scala/whisk/core/entity/MemoryLimit.scala | 8 ++++----
.../main/scala/whisk/core/entity/TimeLimit.scala | 2 +-
.../scala/whisk/core/controller/Controller.scala | 24 +++++++++++++++++++---
.../actionContainers/BasicActionRunnerTests.scala | 23 ++++++++++++++++++---
.../test/scala/system/basic/WskActionTests.scala | 2 --
.../test/scala/system/basic/WskSequenceTests.scala | 15 ++++++++------
.../core/controller/test/ActionsApiTests.scala | 5 +++--
.../core/controller/test/ControllerApiTests.scala | 20 ++++++++++--------
9 files changed, 74 insertions(+), 33 deletions(-)
diff --git a/common/scala/src/main/scala/whisk/core/entity/LogLimit.scala b/common/scala/src/main/scala/whisk/core/entity/LogLimit.scala
index 6f3abef..a78931e 100644
--- a/common/scala/src/main/scala/whisk/core/entity/LogLimit.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/LogLimit.scala
@@ -46,11 +46,11 @@ protected[core] class LogLimit private (val megabytes: Int) extends AnyVal {
}
protected[core] object LogLimit extends ArgNormalizer[LogLimit] {
- private val logLimitConfig = loadConfigOrThrow[MemoryLimitConfig](ConfigKeys.logLimit)
+ val config = loadConfigOrThrow[MemoryLimitConfig](ConfigKeys.logLimit)
- protected[core] val minLogSize: ByteSize = logLimitConfig.min
- protected[core] val maxLogSize: ByteSize = logLimitConfig.max
- protected[core] val stdLogSize: ByteSize = logLimitConfig.std
+ protected[core] val minLogSize: ByteSize = config.min
+ protected[core] val maxLogSize: ByteSize = config.max
+ protected[core] val stdLogSize: ByteSize = config.std
/** Gets LogLimit with default log limit */
protected[core] def apply(): LogLimit = LogLimit(stdLogSize)
diff --git a/common/scala/src/main/scala/whisk/core/entity/MemoryLimit.scala b/common/scala/src/main/scala/whisk/core/entity/MemoryLimit.scala
index 798cf75..80cc9f8 100644
--- a/common/scala/src/main/scala/whisk/core/entity/MemoryLimit.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/MemoryLimit.scala
@@ -42,11 +42,11 @@ case class MemoryLimitConfig(min: ByteSize, max: ByteSize, std: ByteSize)
protected[entity] class MemoryLimit private (val megabytes: Int) extends AnyVal
protected[core] object MemoryLimit extends ArgNormalizer[MemoryLimit] {
- private val memoryConfig = loadConfigOrThrow[MemoryLimitConfig](ConfigKeys.memory)
+ val config = loadConfigOrThrow[MemoryLimitConfig](ConfigKeys.memory)
- protected[core] val minMemory: ByteSize = memoryConfig.min
- protected[core] val maxMemory: ByteSize = memoryConfig.max
- protected[core] val stdMemory: ByteSize = memoryConfig.std
+ protected[core] val minMemory: ByteSize = config.min
+ protected[core] val maxMemory: ByteSize = config.max
+ protected[core] val stdMemory: ByteSize = config.std
/** Gets MemoryLimit with default value */
protected[core] def apply(): MemoryLimit = MemoryLimit(stdMemory)
diff --git a/common/scala/src/main/scala/whisk/core/entity/TimeLimit.scala b/common/scala/src/main/scala/whisk/core/entity/TimeLimit.scala
index 4819404..77b42b4 100644
--- a/common/scala/src/main/scala/whisk/core/entity/TimeLimit.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/TimeLimit.scala
@@ -47,7 +47,7 @@ protected[entity] class TimeLimit private (val duration: FiniteDuration) extends
case class TimeLimitConfig(max: FiniteDuration, min: FiniteDuration, std: FiniteDuration)
protected[core] object TimeLimit extends ArgNormalizer[TimeLimit] {
- private val config = loadConfigOrThrow[TimeLimitConfig](ConfigKeys.timeLimit)
+ val config = loadConfigOrThrow[TimeLimitConfig](ConfigKeys.timeLimit)
protected[core] val MIN_DURATION: FiniteDuration = config.min
protected[core] val MAX_DURATION: FiniteDuration = config.max
diff --git a/core/controller/src/main/scala/whisk/core/controller/Controller.scala b/core/controller/src/main/scala/whisk/core/controller/Controller.scala
index e53936b..4b4fc37 100644
--- a/core/controller/src/main/scala/whisk/core/controller/Controller.scala
+++ b/core/controller/src/main/scala/whisk/core/controller/Controller.scala
@@ -159,7 +159,13 @@ class Controller(val instance: ControllerInstanceId,
}
// controller top level info
- private val info = Controller.info(whiskConfig, runtimes, List(apiV1.basepath()))
+ private val info = Controller.info(
+ whiskConfig,
+ TimeLimit.config,
+ MemoryLimit.config,
+ LogLimit.config,
+ runtimes,
+ List(apiV1.basepath()))
}
/**
@@ -179,7 +185,12 @@ object Controller {
SpiLoader.get[LoadBalancerProvider].requiredProperties ++
EntitlementProvider.requiredProperties
- private def info(config: WhiskConfig, runtimes: Runtimes, apis: List[String]) =
+ private def info(config: WhiskConfig,
+ timeLimit: TimeLimitConfig,
+ memLimit: MemoryLimitConfig,
+ logLimit: MemoryLimitConfig,
+ runtimes: Runtimes,
+ apis: List[String]) =
JsObject(
"description" -> "OpenWhisk".toJson,
"support" -> JsObject(
@@ -189,7 +200,14 @@ object Controller {
"limits" -> JsObject(
"actions_per_minute" -> config.actionInvokePerMinuteLimit.toInt.toJson,
"triggers_per_minute" -> config.triggerFirePerMinuteLimit.toInt.toJson,
- "concurrent_actions" -> config.actionInvokeConcurrentLimit.toInt.toJson),
+ "concurrent_actions" -> config.actionInvokeConcurrentLimit.toInt.toJson,
+ "sequence_length" -> config.actionSequenceLimit.toInt.toJson,
+ "min_action_duration" -> timeLimit.min.toMillis.toJson,
+ "max_action_duration" -> timeLimit.max.toMillis.toJson,
+ "min_action_memory" -> memLimit.min.toBytes.toJson,
+ "max_action_memory" -> memLimit.max.toBytes.toJson,
+ "min_action_logs" -> logLimit.min.toBytes.toJson,
+ "max_action_logs" -> logLimit.max.toBytes.toJson),
"runtimes" -> runtimes.toJson)
def main(args: Array[String]): Unit = {
diff --git a/tests/src/test/scala/actionContainers/BasicActionRunnerTests.scala b/tests/src/test/scala/actionContainers/BasicActionRunnerTests.scala
index a8eb90c..7831f67 100644
--- a/tests/src/test/scala/actionContainers/BasicActionRunnerTests.scala
+++ b/tests/src/test/scala/actionContainers/BasicActionRunnerTests.scala
@@ -43,6 +43,13 @@ trait BasicActionRunnerTests extends ActionProxyContainerTestUtils {
def testNoSourceOrExec: TestConfig
/**
+ * Runs tests for actions which receive an empty code initializer (exec with code equal to the empty string).
+ *
+ * @param stub true if the proxy provides a stub
+ */
+ def testNoSource = testNoSourceOrExec
+
+ /**
* Runs tests for actions which do not return a dictionary and confirms expected error messages.
*
* @param code code to execute, should not return a JSON object
@@ -114,7 +121,7 @@ trait BasicActionRunnerTests extends ActionProxyContainerTestUtils {
behavior of "runtime proxy"
it should "handle initialization with no code" in {
- val config = testNoSourceOrExec
+ val config = testNoSource
val (out, err) = withActionContainer() { c =>
val (initCode, out) = c.init(initPayload("", ""))
@@ -182,7 +189,7 @@ trait BasicActionRunnerTests extends ActionProxyContainerTestUtils {
checkStreams(out, err, {
case (o, e) =>
(o + e) should include(errorMessage)
- }, sentinelCount = if (config.skipTest) 1 else 0)
+ }, sentinelCount = 0)
}
it should s"invoke non-standard entry point" in {
@@ -290,6 +297,7 @@ trait BasicActionRunnerTests extends ActionProxyContainerTestUtils {
it should s"echo a large input" in {
val config = testLargeInput
+ var passed = true
val (out, err) = withActionContainer() { c =>
val (initCode, _) = c.init(initPayload(config.code, config.main))
@@ -297,7 +305,16 @@ trait BasicActionRunnerTests extends ActionProxyContainerTestUtils {
val arg = JsObject("arg" -> JsString(("a" * 1048561)))
val (_, runRes) = c.run(runPayload(arg))
- runRes.get shouldBe arg
+ if (runRes.get != arg) {
+ println(s"result did not match: ${runRes.get}")
+ passed = false
+ }
+ }
+
+ if (!passed) {
+ println(out)
+ println(err)
+ assert(false)
}
}
diff --git a/tests/src/test/scala/system/basic/WskActionTests.scala b/tests/src/test/scala/system/basic/WskActionTests.scala
index c499f50..5108c0f 100644
--- a/tests/src/test/scala/system/basic/WskActionTests.scala
+++ b/tests/src/test/scala/system/basic/WskActionTests.scala
@@ -41,8 +41,6 @@ class WskActionTests extends TestHelpers with WskTestHelpers with JsHelpers with
assetHelper.withCleaner(wsk.action, name) { (action, _) =>
action.create(name, Some(TestUtils.getTestActionFilename("empty.js")))
}
- val rr = wsk.action.get(name)
- wsk.parseJsonString(rr.stdout).getFieldPath("exec", "code") shouldBe Some(JsString(""))
}
it should "invoke an action returning a promise" in withAssetCleaner(wskprops) { (wp, assetHelper) =>
diff --git a/tests/src/test/scala/system/basic/WskSequenceTests.scala b/tests/src/test/scala/system/basic/WskSequenceTests.scala
index b264acd..0e2b28e 100644
--- a/tests/src/test/scala/system/basic/WskSequenceTests.scala
+++ b/tests/src/test/scala/system/basic/WskSequenceTests.scala
@@ -20,6 +20,8 @@ package system.basic
import java.time.Instant
import java.util.Date
+import com.jayway.restassured.RestAssured
+
import scala.concurrent.duration.DurationInt
import scala.language.postfixOps
import scala.util.matching.Regex
@@ -30,23 +32,20 @@ import common.TestUtils._
import common.rest.WskRestOperations
import spray.json._
import spray.json.DefaultJsonProtocol._
-import whisk.core.WhiskConfig
+import system.rest.RestUtil
import whisk.http.Messages.sequenceIsTooLong
/**
* Tests sequence execution
*/
@RunWith(classOf[JUnitRunner])
-class WskSequenceTests extends TestHelpers with WskTestHelpers with StreamLogging with WskActorSystem {
+class WskSequenceTests extends TestHelpers with WskTestHelpers with StreamLogging with RestUtil with WskActorSystem {
implicit val wskprops = WskProps()
val wsk: WskOperations = new WskRestOperations
- val whiskConfig = new WhiskConfig(Map(WhiskConfig.actionSequenceMaxLimit -> null))
val allowedActionDuration = 120 seconds
val shortDuration = 10 seconds
- assert(whiskConfig.isValid)
-
behavior of "Wsk Sequence"
it should "invoke a sequence with normal payload and payload with error field" in withAssetCleaner(wskprops) {
@@ -189,7 +188,11 @@ class WskSequenceTests extends TestHelpers with WskTestHelpers with StreamLoggin
result.fields.get("payload") shouldBe Some(argsJson)
}
// update x with limit echo
- val limit = whiskConfig.actionSequenceLimit.toInt
+ val limit: Int = {
+ val response = RestAssured.given.config(sslconfig).get(getServiceURL)
+ response.statusCode should be(200)
+ response.body.asString.parseJson.asJsObject.fields("limits").asJsObject.fields("sequence_length").convertTo[Int]
+ }
val manyEcho = for (i <- 1 to limit) yield echo
wsk.action.create(xName, Some(manyEcho.mkString(",")), kind = Some("sequence"), update = true)
diff --git a/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
index 8eddc51..9b54b0a 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
@@ -525,8 +525,9 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi {
it should "put should accept request with missing optional properties" in {
implicit val tid = transid()
- val action = WhiskAction(namespace, aname(), jsDefault("??"))
- val content = WhiskActionPut(Some(action.exec))
+ val action = WhiskAction(namespace, aname(), jsDefault(""))
+ // only a kind must be defined (code otherwise could be empty)
+ val content = JsObject("exec" -> JsObject("code" -> "".toJson, "kind" -> action.exec.kind.toJson))
Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check {
deleteAction(action.docid)
status should be(OK)
diff --git a/tests/src/test/scala/whisk/core/controller/test/ControllerApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/ControllerApiTests.scala
index 351702e..00b5c4d 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ControllerApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ControllerApiTests.scala
@@ -21,17 +21,12 @@ import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org.scalatest.Matchers
import org.scalatest.junit.JUnitRunner
-
import com.jayway.restassured.RestAssured
-
import common.StreamLogging
-
import spray.json._
import spray.json.DefaultJsonProtocol._
-
import whisk.core.WhiskConfig
-import whisk.core.entity.ExecManifest
-
+import whisk.core.entity.{ExecManifest, LogLimit, MemoryLimit, TimeLimit}
import system.rest.RestUtil
/**
@@ -47,8 +42,10 @@ class ControllerApiTests extends FlatSpec with RestUtil with Matchers with Strea
WhiskConfig.actionInvokePerMinuteLimit -> null,
WhiskConfig.triggerFirePerMinuteLimit -> null,
WhiskConfig.actionInvokeConcurrentLimit -> null,
- WhiskConfig.runtimesManifest -> null))
+ WhiskConfig.runtimesManifest -> null,
+ WhiskConfig.actionSequenceMaxLimit -> null))
ExecManifest.initialize(config) should be a 'success
+
val expectedJson = JsObject(
"support" -> JsObject(
"github" -> "https://github.com/apache/incubator-openwhisk/issues".toJson,
@@ -59,7 +56,14 @@ class ControllerApiTests extends FlatSpec with RestUtil with Matchers with Strea
"limits" -> JsObject(
"actions_per_minute" -> config.actionInvokePerMinuteLimit.toInt.toJson,
"triggers_per_minute" -> config.triggerFirePerMinuteLimit.toInt.toJson,
- "concurrent_actions" -> config.actionInvokeConcurrentLimit.toInt.toJson))
+ "concurrent_actions" -> config.actionInvokeConcurrentLimit.toInt.toJson,
+ "sequence_length" -> config.actionSequenceLimit.toInt.toJson,
+ "min_action_duration" -> TimeLimit.config.min.toMillis.toJson,
+ "max_action_duration" -> TimeLimit.config.max.toMillis.toJson,
+ "min_action_memory" -> MemoryLimit.config.min.toBytes.toJson,
+ "max_action_memory" -> MemoryLimit.config.max.toBytes.toJson,
+ "min_action_logs" -> LogLimit.config.min.toBytes.toJson,
+ "max_action_logs" -> LogLimit.config.max.toBytes.toJson))
response.statusCode should be(200)
response.body.asString.parseJson shouldBe (expectedJson)
}