You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openwhisk.apache.org by ra...@apache.org on 2018/02/13 19:53:59 UTC
[incubator-openwhisk] branch master updated: Add binary, image,
and main properties to WhiskActionMetaData (#3109)
This is an automated email from the ASF dual-hosted git repository.
rabbah 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 a2dcace Add binary, image, and main properties to WhiskActionMetaData (#3109)
a2dcace is described below
commit a2dcace3d4cbef737cb5875c758f7e5d2b6d9f3c
Author: James Dubee <jw...@us.ibm.com>
AuthorDate: Tue Feb 13 14:53:57 2018 -0500
Add binary, image, and main properties to WhiskActionMetaData (#3109)
Make the reduced action view more like the full view.
---
.../src/main/scala/whisk/core/entity/Exec.scala | 64 +++++++--
.../core/controller/test/ActionsApiTests.scala | 143 ++++++++++++++++++---
.../core/controller/test/WebActionsApiTests.scala | 2 +-
.../scala/whisk/core/entity/test/ExecHelpers.scala | 18 ++-
4 files changed, 196 insertions(+), 31 deletions(-)
diff --git a/common/scala/src/main/scala/whisk/core/entity/Exec.scala b/common/scala/src/main/scala/whisk/core/entity/Exec.scala
index bf066f6..8f31812 100644
--- a/common/scala/src/main/scala/whisk/core/entity/Exec.scala
+++ b/common/scala/src/main/scala/whisk/core/entity/Exec.scala
@@ -95,9 +95,23 @@ sealed abstract class CodeExec[+T <% SizeConversion] extends Exec {
sealed abstract class ExecMetaData extends ExecMetaDataBase {
+ /** An entrypoint (typically name of 'main' function). 'None' means a default value will be used. */
+ val entryPoint: Option[String]
+
+ /** The runtime image (either built-in or a public image). */
+ val image: ImageName
+
/** Indicates if a container image is required from the registry to execute the action. */
val pull: Boolean
+ /**
+ * Indicates whether the code is stored in a text-readable or binary format.
+ * The binary bit may be read from the database but currently it is always computed
+ * when the "code" is moved to an attachment this may get changed to avoid recomputing
+ * the binary property.
+ */
+ val binary: Boolean
+
override def size = 0.B
}
@@ -114,8 +128,12 @@ protected[core] case class CodeExecAsString(manifest: RuntimeManifest,
override def codeAsJson = JsString(code)
}
-protected[core] case class CodeExecMetaDataAsString(manifest: RuntimeManifest) extends ExecMetaData {
+protected[core] case class CodeExecMetaDataAsString(manifest: RuntimeManifest,
+ override val binary: Boolean = false,
+ override val entryPoint: Option[String])
+ extends ExecMetaData {
override val kind = manifest.kind
+ override val image = manifest.image
override val deprecated = manifest.deprecated.getOrElse(false)
override val pull = false
}
@@ -144,8 +162,12 @@ protected[core] case class CodeExecAsAttachment(manifest: RuntimeManifest,
}
}
-protected[core] case class CodeExecMetaDataAsAttachment(manifest: RuntimeManifest) extends ExecMetaData {
+protected[core] case class CodeExecMetaDataAsAttachment(manifest: RuntimeManifest,
+ override val binary: Boolean = false,
+ override val entryPoint: Option[String])
+ extends ExecMetaData {
override val kind = manifest.kind
+ override val image = manifest.image
override val deprecated = manifest.deprecated.getOrElse(false)
override val pull = false
}
@@ -168,7 +190,11 @@ protected[core] case class BlackBoxExec(override val image: ImageName,
override def size = super.size + image.publicImageName.sizeInBytes
}
-protected[core] case class BlackBoxExecMetaData(val native: Boolean) extends ExecMetaData {
+protected[core] case class BlackBoxExecMetaData(override val image: ImageName,
+ override val entryPoint: Option[String],
+ val native: Boolean,
+ override val binary: Boolean = false)
+ extends ExecMetaData {
override val kind = ExecMetaDataBase.BLACKBOX
override val deprecated = false
override val pull = !native
@@ -334,21 +360,24 @@ protected[core] object ExecMetaDataBase extends ArgNormalizer[ExecMetaDataBase]
override def write(e: ExecMetaDataBase) = e match {
case c: CodeExecMetaDataAsString =>
- val base = Map("kind" -> JsString(c.kind))
- JsObject(base)
+ val base = Map("kind" -> JsString(c.kind), "binary" -> JsBoolean(c.binary))
+ val main = c.entryPoint.map("main" -> JsString(_))
+ JsObject(base ++ main)
case a: CodeExecMetaDataAsAttachment =>
val base =
- Map("kind" -> JsString(a.kind))
- JsObject(base)
+ Map("kind" -> JsString(a.kind), "binary" -> JsBoolean(a.binary))
+ val main = a.entryPoint.map("main" -> JsString(_))
+ JsObject(base ++ main)
case s @ SequenceExecMetaData(comp) =>
JsObject("kind" -> JsString(s.kind), "components" -> comp.map(_.qualifiedNameWithLeadingSlash).toJson)
case b: BlackBoxExecMetaData =>
val base =
- Map("kind" -> JsString(b.kind))
- JsObject(base)
+ Map("kind" -> JsString(b.kind), "image" -> JsString(b.image.publicImageName), "binary" -> JsBoolean(b.binary))
+ val main = b.entryPoint.map("main" -> JsString(_))
+ JsObject(base ++ main)
}
override def read(v: JsValue) = {
@@ -368,6 +397,11 @@ protected[core] object ExecMetaDataBase extends ArgNormalizer[ExecMetaDataBase]
case None => None
}
+ lazy val binary: Boolean = obj.fields.get("binary") match {
+ case Some(JsBoolean(b)) => b
+ case _ => throw new DeserializationException("'binary' must be a boolean defined in 'exec'")
+ }
+
kind match {
case ExecMetaDataBase.SEQUENCE =>
val comp: Vector[FullyQualifiedEntityName] = obj.fields.get("components") match {
@@ -385,7 +419,7 @@ protected[core] object ExecMetaDataBase extends ArgNormalizer[ExecMetaDataBase]
s"'image' must be a string defined in 'exec' for '${Exec.BLACKBOX}' actions")
}
val native = execManifests.skipDockerPull(image)
- BlackBoxExecMetaData(native)
+ BlackBoxExecMetaData(image, optMainField, native, binary)
case _ =>
// map "default" virtual runtime versions to the currently blessed actual runtime version
@@ -396,10 +430,16 @@ protected[core] object ExecMetaDataBase extends ArgNormalizer[ExecMetaDataBase]
manifest.attached
.map { a =>
- CodeExecMetaDataAsAttachment(manifest)
+ val main = optMainField.orElse {
+ if (manifest.requireMain.exists(identity)) {
+ throw new DeserializationException(s"'main' must be a string defined in 'exec' for '$kind' actions")
+ } else None
+ }
+
+ CodeExecMetaDataAsAttachment(manifest, binary, main)
}
.getOrElse {
- CodeExecMetaDataAsString(manifest)
+ CodeExecMetaDataAsString(manifest, binary, optMainField)
}
}
}
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 9018759..fb00184 100644
--- a/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/ActionsApiTests.scala
@@ -173,26 +173,136 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi {
}
}
+ def getExecPermutations() = {
+ implicit val tid = transid()
+
+ // BlackBox: binary: true, main: bbMain
+ val bbAction1 = WhiskAction(namespace, aname(), bb("bb", "RHViZWU=", Some("bbMain")))
+ val bbAction1Content = Map("exec" -> Map(
+ "kind" -> Exec.BLACKBOX,
+ "code" -> "RHViZWU=",
+ "image" -> "bb",
+ "main" -> "bbMain")).toJson.asJsObject
+ val bbAction1ExecMetaData = blackBoxMetaData("bb", Some("bbMain"), true)
+
+ // BlackBox: binary: false, main: bbMain
+ val bbAction2 = WhiskAction(namespace, aname(), bb("bb", "", Some("bbMain")))
+ val bbAction2Content =
+ Map("exec" -> Map("kind" -> Exec.BLACKBOX, "code" -> "", "image" -> "bb", "main" -> "bbMain")).toJson.asJsObject
+ val bbAction2ExecMetaData = blackBoxMetaData("bb", Some("bbMain"), false)
+
+ // BlackBox: binary: true, no main
+ val bbAction3 = WhiskAction(namespace, aname(), bb("bb", "RHViZWU="))
+ val bbAction3Content =
+ Map("exec" -> Map("kind" -> Exec.BLACKBOX, "code" -> "RHViZWU=", "image" -> "bb")).toJson.asJsObject
+ val bbAction3ExecMetaData = blackBoxMetaData("bb", None, true)
+
+ // BlackBox: binary: false, no main
+ val bbAction4 = WhiskAction(namespace, aname(), bb("bb", ""))
+ val bbAction4Content = Map("exec" -> Map("kind" -> Exec.BLACKBOX, "code" -> "", "image" -> "bb")).toJson.asJsObject
+ val bbAction4ExecMetaData = blackBoxMetaData("bb", None, false)
+
+ // Attachment: binary: true, main: javaMain
+ val javaAction1 = WhiskAction(namespace, aname(), javaDefault("RHViZWU=", Some("javaMain")))
+ val javaAction1Content =
+ Map("exec" -> Map("kind" -> JAVA_DEFAULT, "code" -> "RHViZWU=", "main" -> "javaMain")).toJson.asJsObject
+ val javaAction1ExecMetaData = javaMetaData(Some("javaMain"), true)
+
+ // String: binary: true, main: jsMain
+ val jsAction1 = WhiskAction(namespace, aname(), jsDefault("RHViZWU=", Some("jsMain")))
+ val jsAction1Content =
+ Map("exec" -> Map("kind" -> NODEJS6, "code" -> "RHViZWU=", "main" -> "jsMain")).toJson.asJsObject
+ val jsAction1ExecMetaData = js6MetaData(Some("jsMain"), true)
+
+ // String: binary: false, main: jsMain
+ val jsAction2 = WhiskAction(namespace, aname(), jsDefault("", Some("jsMain")))
+ val jsAction2Content = Map("exec" -> Map("kind" -> NODEJS6, "code" -> "", "main" -> "jsMain")).toJson.asJsObject
+ val jsAction2ExecMetaData = js6MetaData(Some("jsMain"), false)
+
+ // String: binary: true, no main
+ val jsAction3 = WhiskAction(namespace, aname(), jsDefault("RHViZWU="))
+ val jsAction3Content = Map("exec" -> Map("kind" -> NODEJS6, "code" -> "RHViZWU=")).toJson.asJsObject
+ val jsAction3ExecMetaData = js6MetaData(None, true)
+
+ // String: binary: false, no main
+ val jsAction4 = WhiskAction(namespace, aname(), jsDefault(""))
+ val jsAction4Content = Map("exec" -> Map("kind" -> NODEJS6, "code" -> "")).toJson.asJsObject
+ val jsAction4ExecMetaData = js6MetaData(None, false)
+
+ // Sequence
+ val component = WhiskAction(namespace, aname(), jsDefault("??"))
+ put(entityStore, component)
+ val components = Vector(s"/$namespace/${component.name}").map(stringToFullyQualifiedName(_))
+ val seqAction = WhiskAction(namespace, aname(), sequence(components), seqParameters(components))
+ val seqActionContent = JsObject(
+ "exec" -> JsObject("kind" -> "sequence".toJson, "components" -> JsArray(s"/$namespace/${component.name}".toJson)))
+ val seqActionExecMetaData = sequenceMetaData(components)
+
+ Seq(
+ (bbAction1, bbAction1Content, bbAction1ExecMetaData),
+ (bbAction2, bbAction2Content, bbAction2ExecMetaData),
+ (bbAction3, bbAction3Content, bbAction3ExecMetaData),
+ (bbAction4, bbAction4Content, bbAction4ExecMetaData),
+ (javaAction1, javaAction1Content, javaAction1ExecMetaData),
+ (jsAction1, jsAction1Content, jsAction1ExecMetaData),
+ (jsAction2, jsAction2Content, jsAction2ExecMetaData),
+ (jsAction3, jsAction3Content, jsAction3ExecMetaData),
+ (jsAction4, jsAction4Content, jsAction4ExecMetaData),
+ (seqAction, seqActionContent, seqActionExecMetaData))
+ }
+
it should "get action using code query parameter" in {
implicit val tid = transid()
- val action = WhiskAction(namespace, aname(), jsDefault("??"), Parameters("x", "b"))
- put(entityStore, action)
+ getExecPermutations.foreach {
+ case (action, content, execMetaData) =>
+ val expectedWhiskAction = WhiskAction(
+ action.namespace,
+ action.name,
+ action.exec,
+ action.parameters,
+ action.limits,
+ action.version,
+ action.publish,
+ action.annotations ++ Parameters(WhiskAction.execFieldName, action.exec.kind))
- Get(s"$collectionPath/${action.name}?code=false") ~> Route.seal(routes(creds)) ~> check {
- status should be(OK)
- val response = responseAs[JsObject]
- response.fields("exec").asJsObject.fields should not(contain key "code")
- responseAs[WhiskActionMetaData] shouldBe a[WhiskActionMetaData]
- }
+ val expectedWhiskActionMetaData = WhiskActionMetaData(
+ action.namespace,
+ action.name,
+ execMetaData,
+ action.parameters,
+ action.limits,
+ action.version,
+ action.publish,
+ action.annotations ++ Parameters(WhiskActionMetaData.execFieldName, action.exec.kind))
- Seq(s"$collectionPath/${action.name}", s"$collectionPath/${action.name}?code=true").foreach { path =>
- Get(path) ~> Route.seal(routes(creds)) ~> check {
- status should be(OK)
- val response = responseAs[JsObject]
- response.fields("exec").asJsObject.fields("code") should be("??".toJson)
- responseAs[WhiskAction] shouldBe a[WhiskAction]
- }
+ Put(s"$collectionPath/${action.name}", content) ~> Route.seal(routes(creds)) ~> check {
+ status should be(OK)
+ val response = responseAs[WhiskAction]
+ response should be(expectedWhiskAction)
+ }
+
+ Get(s"$collectionPath/${action.name}?code=false") ~> Route.seal(routes(creds)) ~> check {
+ status should be(OK)
+ val responseJson = responseAs[JsObject]
+ responseJson.fields("exec").asJsObject.fields should not(contain key "code")
+ val response = responseAs[WhiskActionMetaData]
+ response should be(expectedWhiskActionMetaData)
+ }
+
+ Seq(s"$collectionPath/${action.name}", s"$collectionPath/${action.name}?code=true").foreach { path =>
+ Get(path) ~> Route.seal(routes(creds)) ~> check {
+ status should be(OK)
+ val response = responseAs[WhiskAction]
+ response should be(expectedWhiskAction)
+ }
+ }
+
+ Delete(s"$collectionPath/${action.name}") ~> Route.seal(routes(creds)) ~> check {
+ status should be(OK)
+ val response = responseAs[WhiskAction]
+ response should be(expectedWhiskAction)
+ }
}
}
@@ -437,7 +547,8 @@ class ActionsApiTests extends ControllerTestCommon with WhiskActionsApi {
}
private implicit val fqnSerdes = FullyQualifiedEntityName.serdes
- private def seqParameters(seq: Vector[FullyQualifiedEntityName]) = Parameters("_actions", seq.toJson)
+ private def seqParameters(seq: Vector[FullyQualifiedEntityName]) =
+ Parameters("_actions", seq.map("/" + _.asString).toJson)
// this test is sneaky; the installation of the sequence is done directly in the db
// and api checks are skipped
diff --git a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
index 57c8401..2bcfe91 100644
--- a/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
+++ b/tests/src/test/scala/whisk/core/controller/test/WebActionsApiTests.scala
@@ -190,7 +190,7 @@ trait WebActionsApiBaseTests extends ControllerTestCommon with BeforeAndAfterEac
WhiskActionMetaData(
actionName.path,
actionName.name,
- js6MetaData(),
+ js6MetaData(binary = false),
defaultActionParameters,
annotations = {
if (actionName.name.asString.startsWith("export_")) {
diff --git a/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala b/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala
index c0f4ea8..688fcd5 100644
--- a/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala
+++ b/tests/src/test/scala/whisk/core/entity/test/ExecHelpers.scala
@@ -68,9 +68,11 @@ trait ExecHelpers extends Matchers with WskActorSystem with StreamLogging {
js6(code, main)
}
- protected def js6MetaData(main: Option[String] = None) = {
+ protected def js6MetaData(main: Option[String] = None, binary: Boolean) = {
CodeExecMetaDataAsString(
- RuntimeManifest(NODEJS6, imagename(NODEJS6), default = Some(true), deprecated = Some(false)))
+ RuntimeManifest(NODEJS6, imagename(NODEJS6), default = Some(true), deprecated = Some(false)),
+ binary,
+ main.map(_.trim))
}
protected def javaDefault(code: String, main: Option[String] = None) = {
@@ -80,6 +82,12 @@ trait ExecHelpers extends Matchers with WskActorSystem with StreamLogging {
CodeExecAsAttachment(manifest, attachment, main.map(_.trim))
}
+ protected def javaMetaData(main: Option[String] = None, binary: Boolean) = {
+ val manifest = ExecManifest.runtimesManifest.resolveDefaultRuntime(JAVA_DEFAULT).get
+
+ CodeExecMetaDataAsAttachment(manifest, binary, main.map(_.trim))
+ }
+
protected def swift(code: String, main: Option[String] = None) = {
CodeExecAsString(RuntimeManifest(SWIFT, imagename(SWIFT), deprecated = Some(true)), trim(code), main.map(_.trim))
}
@@ -94,9 +102,15 @@ trait ExecHelpers extends Matchers with WskActorSystem with StreamLogging {
protected def sequence(components: Vector[FullyQualifiedEntityName]) = SequenceExec(components)
+ protected def sequenceMetaData(components: Vector[FullyQualifiedEntityName]) = SequenceExecMetaData(components)
+
protected def bb(image: String) = BlackBoxExec(ExecManifest.ImageName(trim(image)), None, None, false)
protected def bb(image: String, code: String, main: Option[String] = None) = {
BlackBoxExec(ExecManifest.ImageName(trim(image)), Some(trim(code)).filter(_.nonEmpty), main, false)
}
+
+ protected def blackBoxMetaData(image: String, main: Option[String] = None, binary: Boolean) = {
+ BlackBoxExecMetaData(ExecManifest.ImageName(trim(image)), main, false, binary)
+ }
}
--
To stop receiving notification emails like this one, please contact
rabbah@apache.org.