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