From 71e26916ff32590fb1343bdc3814cab592c52e8d Mon Sep 17 00:00:00 2001 From: Rodric Rabbah Date: Fri, 18 May 2018 13:33:45 -0400 Subject: [PATCH] Adjust invoker playbook to pull runtime and blackbox docker images. Remove default runtime prefix and tag; the runtimes.json file should fully specify these. Remove docker.{registry,prefix,tax} entanglement with runtimes as these are used for the system images not the runtimes. Optionally specify a runtimes.registry to pull images from there instead of dockerhub. --- ansible/files/runtimes.json | 52 ++++++++++++++----- ansible/group_vars/all | 19 ++++--- ansible/roles/invoker/tasks/deploy.yml | 30 ++++++----- .../scala/src/main/resources/application.conf | 2 - .../main/scala/whisk/core/WhiskConfig.scala | 10 +--- .../whisk/core/entity/ExecManifest.scala | 32 +++++------- .../core/mesos/MesosContainerFactory.scala | 2 +- .../docker/DockerContainerFactory.scala | 2 +- .../KubernetesContainerFactory.scala | 2 +- .../scala/whisk/core/invoker/Invoker.scala | 5 +- .../scala/whisk/core/WhiskConfigTests.scala | 6 --- .../test/DockerContainerFactoryTests.scala | 6 +-- .../test/MesosContainerFactoryTest.scala | 8 +-- .../core/entity/test/ExecManifestTests.scala | 44 +++++++--------- 14 files changed, 114 insertions(+), 106 deletions(-) diff --git a/ansible/files/runtimes.json b/ansible/files/runtimes.json index 44cb30f2c19..8b4673d2093 100644 --- a/ansible/files/runtimes.json +++ b/ansible/files/runtimes.json @@ -4,7 +4,9 @@ { "kind": "nodejs", "image": { - "name": "nodejsaction" + "prefix": "openwhisk", + "name": "nodejsaction", + "tag": "latest" }, "deprecated": true }, @@ -12,7 +14,9 @@ "kind": "nodejs:6", "default": true, "image": { - "name": "nodejs6action" + "prefix": "openwhisk", + "name": "nodejs6action", + "tag": "latest" }, "deprecated": false, "stemCells": [{ @@ -24,7 +28,9 @@ "kind": "nodejs:8", "default": false, "image": { - "name": "action-nodejs-v8" + "prefix": "openwhisk", + "name": "action-nodejs-v8", + "tag": "latest" }, "deprecated": false } @@ -33,7 +39,9 @@ { "kind": "python", "image": { - "name": "python2action" + "prefix": "openwhisk", + "name": "python2action", + "tag": "latest" }, "deprecated": false }, @@ -41,14 +49,18 @@ "kind": "python:2", "default": true, "image": { - "name": "python2action" + "prefix": "openwhisk", + "name": "python2action", + "tag": "latest" }, "deprecated": false }, { "kind": "python:3", "image": { - "name": "python3action" + "prefix": "openwhisk", + "name": "python3action", + "tag": "latest" }, "deprecated": false } @@ -57,21 +69,27 @@ { "kind": "swift", "image": { - "name": "swiftaction" + "prefix": "openwhisk", + "name": "swiftaction", + "tag": "latest" }, "deprecated": true }, { "kind": "swift:3", "image": { - "name": "swift3action" + "prefix": "openwhisk", + "name": "swift3action", + "tag": "latest" }, "deprecated": true }, { "kind": "swift:3.1.1", "image": { - "name": "action-swift-v3.1.1" + "prefix": "openwhisk", + "name": "action-swift-v3.1.1", + "tag": "latest" }, "deprecated": false }, @@ -79,7 +97,9 @@ "kind": "swift:4.1", "default": true, "image": { - "name": "action-swift-v4.1" + "prefix": "openwhisk", + "name": "action-swift-v4.1", + "tag": "latest" }, "deprecated": false } @@ -89,7 +109,9 @@ "kind": "java", "default": true, "image": { - "name": "java8action" + "prefix": "openwhisk", + "name": "java8action", + "tag": "latest" }, "deprecated": false, "attached": { @@ -106,14 +128,18 @@ "default": true, "deprecated": false, "image": { - "name": "action-php-v7.1" + "prefix": "openwhisk", + "name": "action-php-v7.1", + "tag": "latest" } } ] }, "blackboxes": [ { - "name": "dockerskeleton" + "prefix": "openwhisk", + "name": "dockerskeleton", + "tag": "latest" } ] } diff --git a/ansible/group_vars/all b/ansible/group_vars/all index 1acdfbbc12d..f4ceacb00b9 100644 --- a/ansible/group_vars/all +++ b/ansible/group_vars/all @@ -29,14 +29,17 @@ whisk: date: "{{ansible_date_time.iso8601}}" ## -# list of supported runtimes (see whisk.core.entity.ExecManifest for schema). -# briefly: -# defaultImagePrefix: the default image prefix when not given explicitly -# defaultImageTag: the default image tag -# runtimes: set of language runtime families grouped by language (e.g., nodejs, python) -# blackboxes: list of pre-populated docker action images as "name" with optional "prefix" and "tag" -# bypassPullForLocalImages: optional, if true, allow images with a prefix that matches {{ docker.image.prefix }} -# to skip docker pull in invoker even if the image is not part of the blackbox set +# configuration parameters related to support runtimes (see whisk.core.entity.ExecManifest for schema of the manifest). +# briefly the parameters are: +# +# runtimes_registry: optional registry (with trailing slack) where to pull docker images from for runtimes and backbox images +# +# skip_pull_runtimes: this will skip pulling the images to the invoker (images must exist there somehow) +# +# runtimes_manifest: set of language runtime families grouped by language (e.g., nodejs, python) and blackbox images to pre-pull +# +# runtimes_bypass_pull_for_local_images: optional, if true, allow images with a prefix that matches +# {{ runtimes_local_image_prefix }} to skip docker pull in invoker even if the image is not part of the blackbox set # runtimesManifest: "{{ runtimes_manifest | default(lookup('file', openwhisk_home ~ '/ansible/files/runtimes.json') | from_json) }}" diff --git a/ansible/roles/invoker/tasks/deploy.yml b/ansible/roles/invoker/tasks/deploy.yml index ee4a79aaf33..0f8fd1e783c 100644 --- a/ansible/roles/invoker/tasks/deploy.yml +++ b/ansible/roles/invoker/tasks/deploy.yml @@ -13,18 +13,28 @@ retries: "{{ docker.pull.retries }}" delay: "{{ docker.pull.delay }}" -- name: "pull runtime action images with tag {{docker.image.tag}}" - shell: "docker pull {{docker_registry}}{{docker.image.prefix}}/{{item}}:{{docker.image.tag}}" - with_items: "{{ runtimesManifest.runtimes.values() | sum(start=[]) | selectattr('deprecated', 'equalto',false) | map(attribute='image.name') | list | unique }}" - when: docker_registry != "" +### +# This task assumes that the images are local to the invoker host already if there is no prefix or tag +# which is usually the case for a local deployment. A distributed deployment will specify the prefix, or tag +# to pull the images from the appropriate registry. If a runtimes_registry is optionally specified, pull images +# from there; this permits a (private) registry to be used for caching the images. The registry if specified +# must include a trailing '/'. +# +- name: "pull runtime action images per manifest" + shell: "docker pull {{runtimes_registry | default()}}{{item.prefix}}/{{item.name}}:{{item.tag | default()}}" + with_items: "{{ runtimesManifest.runtimes.values() | sum(start=[]) | selectattr('deprecated', 'equalto',false) | map(attribute='image') | list | unique }}" + when: skip_pull_runtimes is not defined or skip_pull_runtimes == True retries: "{{ docker.pull.retries }}" delay: "{{ docker.pull.delay }}" -- name: "pull blackboxes action images with tag {{docker.image.tag}}" - shell: "docker pull {{docker_registry}}{{docker.image.prefix}}/{{item.name}}:{{docker.image.tag}}" +### +# See comment above for pulling other runtime images. +# +- name: "pull blackboxes action images per manifest" + shell: "docker pull {{runtimes_registry | default()}}{{item.prefix}}/{{item.name}}:{{item.tag | default()}}" with_items: - "{{ runtimesManifest.blackboxes }}" - when: docker_registry != "" + when: skip_pull_runtimes is not defined or skip_pull_runtimes == True retries: "{{ docker.pull.retries }}" delay: "{{ docker.pull.delay }}" @@ -179,14 +189,10 @@ "WHISK_API_HOST_PROTO": "{{ whisk_api_host_proto | default('https') }}" "WHISK_API_HOST_PORT": "{{ whisk_api_host_port | default('443') }}" "WHISK_API_HOST_NAME": "{{ whisk_api_host_name | default(groups['edge'] | first) }}" + "RUNTIMES_REGISTRY": "{{ runtimes_registry | default('') }}" "RUNTIMES_MANIFEST": "{{ runtimesManifest | to_json }}" - "CONFIG_whisk_runtimes_defaultImagePrefix": "{{ runtimes_default_image_prefix | default() }}" - "CONFIG_whisk_runtimes_defaultImageTag": "{{ runtimes_default_image_tag | default() }}" "CONFIG_whisk_runtimes_bypassPullForLocalImages": "{{ runtimes_bypass_pull_for_local_images | default() }}" "CONFIG_whisk_runtimes_localImagePrefix": "{{ runtimes_local_image_prefix | default() }}" - "DOCKER_REGISTRY": "{{ docker_registry }}" - "DOCKER_IMAGE_PREFIX": "{{ docker.image.prefix }}" - "DOCKER_IMAGE_TAG": "{{ docker.image.tag }}" "CONFIG_whisk_containerFactory_containerArgs_network": "{{ invoker_container_network_name | default('bridge') }}" "INVOKER_CONTAINER_POLICY": "{{ invoker_container_policy_name | default()}}" "CONFIG_whisk_containerPool_numCore": "{{ invoker.numcore }}" diff --git a/common/scala/src/main/resources/application.conf b/common/scala/src/main/resources/application.conf index dbc70c5fd3d..69d4703f3ec 100644 --- a/common/scala/src/main/resources/application.conf +++ b/common/scala/src/main/resources/application.conf @@ -146,8 +146,6 @@ whisk { } # action runtimes configuration runtimes { - default-image-prefix = "openwhisk" - default-image-tag = "latest" bypass-pull-for-local-images = false local-image-prefix = "whisk" } diff --git a/common/scala/src/main/scala/whisk/core/WhiskConfig.scala b/common/scala/src/main/scala/whisk/core/WhiskConfig.scala index 0c937ae372c..70090293409 100644 --- a/common/scala/src/main/scala/whisk/core/WhiskConfig.scala +++ b/common/scala/src/main/scala/whisk/core/WhiskConfig.scala @@ -51,13 +51,9 @@ class WhiskConfig(requiredProperties: Map[String, String], } val servicePort = this(WhiskConfig.servicePort) - val dockerRegistry = this(WhiskConfig.dockerRegistry) val dockerEndpoint = this(WhiskConfig.dockerEndpoint) val dockerPort = this(WhiskConfig.dockerPort) - val dockerImagePrefix = this(WhiskConfig.dockerImagePrefix) - val dockerImageTag = this(WhiskConfig.dockerImageTag) - val invokerName = this(WhiskConfig.invokerName) val wskApiHost = this(WhiskConfig.wskApiProtocol) + "://" + this(WhiskConfig.wskApiHostname) + ":" + this( @@ -77,6 +73,7 @@ class WhiskConfig(requiredProperties: Map[String, String], val dbPrefix = this(WhiskConfig.dbPrefix) val mainDockerEndpoint = this(WhiskConfig.mainDockerEndpoint) + val runtimesRegistry = this(WhiskConfig.runtimesRegistry) val runtimesManifest = this(WhiskConfig.runtimesManifest) val actionInvokePerMinuteLimit = this(WhiskConfig.actionInvokePerMinuteLimit) val actionInvokeConcurrentLimit = this(WhiskConfig.actionInvokeConcurrentLimit) @@ -149,7 +146,6 @@ object WhiskConfig { } val servicePort = "port" - val dockerRegistry = "docker.registry" val dockerPort = "docker.port" val dockerEndpoint = "main.docker.endpoint" @@ -163,9 +159,6 @@ object WhiskConfig { val whiskVersion = Map(whiskVersionDate -> null, whiskVersionBuildno -> null) - val dockerImagePrefix = "docker.image.prefix" - val dockerImageTag = "docker.image.tag" - val invokerName = "invoker.name" val wskApiProtocol = "whisk.api.host.proto" @@ -194,6 +187,7 @@ object WhiskConfig { val kafkaHosts = Map(kafkaHostList -> null) val zookeeperHosts = Map(zookeeperHostList -> null) + val runtimesRegistry = "runtimes.registry" val runtimesManifest = "runtimes.manifest" val actionSequenceMaxLimit = "limits.actions.sequence.maxLength" diff --git a/common/scala/src/main/scala/whisk/core/entity/ExecManifest.scala b/common/scala/src/main/scala/whisk/core/entity/ExecManifest.scala index 7436d167f0c..15c579931f0 100644 --- a/common/scala/src/main/scala/whisk/core/entity/ExecManifest.scala +++ b/common/scala/src/main/scala/whisk/core/entity/ExecManifest.scala @@ -72,16 +72,12 @@ protected[core] object ExecManifest { * @return Runtimes instance */ protected[entity] def runtimes(config: JsObject, runtimeManifestConfig: RuntimeManifestConfig): Try[Runtimes] = Try { - - val prefix = runtimeManifestConfig.defaultImagePrefix - val tag = runtimeManifestConfig.defaultImageTag - val runtimes = config.fields .get("runtimes") .map(_.convertTo[Map[String, Set[RuntimeManifest]]].map { case (name, versions) => RuntimeFamily(name, versions.map { mf => - val img = ImageName(mf.image.name, mf.image.prefix.orElse(prefix), mf.image.tag.orElse(tag)) + val img = ImageName(mf.image.name, mf.image.prefix, mf.image.tag) mf.copy(image = img) }) }.toSet) @@ -89,7 +85,7 @@ protected[core] object ExecManifest { val blackbox = config.fields .get("blackboxes") .map(_.convertTo[Set[ImageName]].map { image => - ImageName(image.name, image.prefix.orElse(prefix), image.tag.orElse(tag)) + ImageName(image.name, image.prefix, image.tag) }) val bypassPullForLocalImages = runtimeManifestConfig.bypassPullForLocalImages @@ -100,16 +96,14 @@ protected[core] object ExecManifest { } /** - * Misc options related to runtime manifests - * @param defaultImagePrefix the default image prefix when not given explicitly - * @param defaultImageTag the default image tag + * Misc options related to runtime manifests. + * * @param bypassPullForLocalImages if true, allow images with a prefix that matches localImagePrefix - * to skip docker pull in invoker even if the image is not part of the blackbox set + * to skip docker pull on invoker even if the image is not part of the blackbox set; + * this is useful for testing with local images that aren't published to the runtimes registry * @param localImagePrefix image prefix for bypassPullForLocalImages */ - protected[core] case class RuntimeManifestConfig(defaultImagePrefix: Option[String] = None, - defaultImageTag: Option[String] = None, - bypassPullForLocalImages: Option[Boolean] = None, + protected[core] case class RuntimeManifestConfig(bypassPullForLocalImages: Option[Boolean] = None, localImagePrefix: Option[String] = None) /** @@ -159,18 +153,18 @@ protected[core] object ExecManifest { } /** - * The internal name of the image for an action kind. It overrides - * the prefix with an internal name. Optionally overrides tag. + * The internal name of the image for an action kind relative to a registry. */ - def localImageName(registry: String, prefix: String, tagOverride: Option[String] = None): String = { + def localImageName(registry: String): String = { val r = Option(registry) .filter(_.nonEmpty) .map { reg => if (reg.endsWith("/")) reg else reg + "/" } .getOrElse("") - val p = Option(prefix).filter(_.nonEmpty).map(_ + "/").getOrElse("") - r + p + name + ":" + tagOverride.orElse(tag).getOrElse(ImageName.defaultImageTag) + val p = prefix.filter(_.nonEmpty).map(_ + "/").getOrElse("") + val t = tag.filter(_.nonEmpty).map(":" + _).getOrElse("") + r + p + name + t } /** @@ -190,7 +184,7 @@ protected[core] object ExecManifest { } protected[core] object ImageName { - protected val defaultImageTag = "latest" + private val defaultImageTag = "latest" private val componentRegex = """([a-z0-9._-]+)""".r private val tagRegex = """([\w.-]{0,128})""".r diff --git a/common/scala/src/main/scala/whisk/core/mesos/MesosContainerFactory.scala b/common/scala/src/main/scala/whisk/core/mesos/MesosContainerFactory.scala index b0d47a90a1f..42232b9d1e3 100644 --- a/common/scala/src/main/scala/whisk/core/mesos/MesosContainerFactory.scala +++ b/common/scala/src/main/scala/whisk/core/mesos/MesosContainerFactory.scala @@ -114,7 +114,7 @@ class MesosContainerFactory(config: WhiskConfig, val image = if (userProvidedImage) { actionImage.publicImageName } else { - actionImage.localImageName(config.dockerRegistry, config.dockerImagePrefix, Some(config.dockerImageTag)) + actionImage.localImageName(config.runtimesRegistry) } val constraintStrings = if (userProvidedImage) { mesosConfig.blackboxConstraints diff --git a/core/invoker/src/main/scala/whisk/core/containerpool/docker/DockerContainerFactory.scala b/core/invoker/src/main/scala/whisk/core/containerpool/docker/DockerContainerFactory.scala index 3f2ee864061..4d4fcf1781a 100644 --- a/core/invoker/src/main/scala/whisk/core/containerpool/docker/DockerContainerFactory.scala +++ b/core/invoker/src/main/scala/whisk/core/containerpool/docker/DockerContainerFactory.scala @@ -61,7 +61,7 @@ class DockerContainerFactory(instance: InstanceId, val image = if (userProvidedImage) { actionImage.publicImageName } else { - actionImage.localImageName(config.dockerRegistry, config.dockerImagePrefix, Some(config.dockerImageTag)) + actionImage.localImageName(config.runtimesRegistry) } DockerContainer.create( diff --git a/core/invoker/src/main/scala/whisk/core/containerpool/kubernetes/KubernetesContainerFactory.scala b/core/invoker/src/main/scala/whisk/core/containerpool/kubernetes/KubernetesContainerFactory.scala index e332b848613..b56a2856cb1 100644 --- a/core/invoker/src/main/scala/whisk/core/containerpool/kubernetes/KubernetesContainerFactory.scala +++ b/core/invoker/src/main/scala/whisk/core/containerpool/kubernetes/KubernetesContainerFactory.scala @@ -69,7 +69,7 @@ class KubernetesContainerFactory(label: String, config: WhiskConfig)(implicit ac val image = if (userProvidedImage) { actionImage.publicImageName } else { - actionImage.localImageName(config.dockerRegistry, config.dockerImagePrefix, Some(config.dockerImageTag)) + actionImage.localImageName(config.runtimesRegistry) } KubernetesContainer.create( diff --git a/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala b/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala index 134aa05ed54..02d08eb0fa9 100644 --- a/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala +++ b/core/invoker/src/main/scala/whisk/core/invoker/Invoker.scala @@ -52,12 +52,11 @@ object Invoker { * An object which records the environment variables required for this component to run. */ def requiredProperties = - Map(servicePort -> 8080.toString(), dockerRegistry -> null, dockerImagePrefix -> null) ++ + Map(servicePort -> 8080.toString, invokerName -> "", runtimesRegistry -> "") ++ ExecManifest.requiredProperties ++ kafkaHosts ++ zookeeperHosts ++ - wskApiHost ++ Map(dockerImageTag -> "latest") ++ - Map(invokerName -> "") + wskApiHost def main(args: Array[String]): Unit = { Kamon.start() diff --git a/tests/src/test/scala/whisk/core/WhiskConfigTests.scala b/tests/src/test/scala/whisk/core/WhiskConfigTests.scala index 7de4141c64d..f75f6585013 100644 --- a/tests/src/test/scala/whisk/core/WhiskConfigTests.scala +++ b/tests/src/test/scala/whisk/core/WhiskConfigTests.scala @@ -82,10 +82,4 @@ class WhiskConfigTests extends FlatSpec with Matchers with StreamLogging { assert(config("d", "a") == "A") assert(config("c", "a") == "A") } - - it should "get property with no value from whisk.properties file" in { - val config = new WhiskConfig(Map(WhiskConfig.dockerRegistry -> null)) - println(s"${WhiskConfig.dockerRegistry} is: '${config.dockerRegistry}'") - assert(config.isValid) - } } diff --git a/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala b/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala index 31139dc8028..a94890b36d6 100644 --- a/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala +++ b/tests/src/test/scala/whisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala @@ -31,7 +31,6 @@ import scala.concurrent.Future import scala.concurrent.duration._ import whisk.common.TransactionId import whisk.core.WhiskConfig -import whisk.core.WhiskConfig._ import whisk.core.containerpool.ContainerAddress import whisk.core.containerpool.ContainerArgsConfig import whisk.core.containerpool.ContainerId @@ -53,8 +52,7 @@ class DockerContainerFactoryTests with WskActorSystem with TimingHelpers { - implicit val config = new WhiskConfig( - ExecManifest.requiredProperties ++ Map(dockerImagePrefix -> "testing", dockerImageTag -> "testtag")) + implicit val config = new WhiskConfig(ExecManifest.requiredProperties) ExecManifest.initialize(config) should be a 'success behavior of "DockerContainerFactory" @@ -69,7 +67,7 @@ class DockerContainerFactoryTests (dockerApiStub .run(_: String, _: Seq[String])(_: TransactionId)) .expects( - image.localImageName(config.dockerRegistry, config.dockerImagePrefix, Some(config.dockerImageTag)), + image.localImageName(config.runtimesRegistry), List( "--cpu-shares", "32", //should be calculated as 1024/(numcore * sharefactor) via ContainerFactory.cpuShare diff --git a/tests/src/test/scala/whisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala b/tests/src/test/scala/whisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala index 51c62c5a662..51d899c865a 100644 --- a/tests/src/test/scala/whisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala +++ b/tests/src/test/scala/whisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala @@ -69,7 +69,7 @@ class MesosContainerFactoryTest def await[A](f: Future[A], timeout: FiniteDuration = 500.milliseconds) = Await.result[A](f, timeout) implicit val wskConfig = - new WhiskConfig(Map(dockerImageTag -> "latest", wskApiHostname -> "apihost") ++ wskApiHost) + new WhiskConfig(Map(wskApiHostname -> "apihost") ++ wskApiHost) var count = 0 var lastTaskId: String = null def testTaskId() = { @@ -141,7 +141,7 @@ class MesosContainerFactoryTest SubmitTask(TaskDef( lastTaskId, "mesosContainer", - "fakeImage:" + wskConfig.dockerImageTag, + "fakeImage", mesosCpus, 1, List(8080), @@ -190,7 +190,7 @@ class MesosContainerFactoryTest SubmitTask(TaskDef( lastTaskId, "mesosContainer", - "fakeImage:" + wskConfig.dockerImageTag, + "fakeImage", mesosCpus, 1, List(8080), @@ -262,7 +262,7 @@ class MesosContainerFactoryTest SubmitTask(TaskDef( lastTaskId, "mesosContainer", - "fakeImage:" + wskConfig.dockerImageTag, + "fakeImage", mesosCpus, 1, List(8080), diff --git a/tests/src/test/scala/whisk/core/entity/test/ExecManifestTests.scala b/tests/src/test/scala/whisk/core/entity/test/ExecManifestTests.scala index 690e4490517..e14c7c46e3f 100644 --- a/tests/src/test/scala/whisk/core/entity/test/ExecManifestTests.scala +++ b/tests/src/test/scala/whisk/core/entity/test/ExecManifestTests.scala @@ -85,7 +85,7 @@ class ExecManifestTests extends FlatSpec with WskActorSystem with StreamLogging runtimes.resolveDefaultRuntime("s1:default") shouldBe Some(s1) } - it should "read a valid configuration without default prefix, default tag" in { + it should "read a valid configuration where an image may omit prefix or tag" in { val i1 = RuntimeManifest("i1", ImageName("???")) val i2 = RuntimeManifest("i2", ImageName("???", Some("ppp")), default = Some(true)) val j1 = RuntimeManifest("j1", ImageName("???", Some("ppp"), Some("ttt"))) @@ -99,14 +99,14 @@ class ExecManifestTests extends FlatSpec with WskActorSystem with StreamLogging "js" -> Set(j1).toJson, "ks" -> Set(k1).toJson, "ss" -> Set(s1).toJson)) - val rmc = RuntimeManifestConfig(defaultImagePrefix = Some("pre"), defaultImageTag = Some("test")) + val rmc = RuntimeManifestConfig() val runtimes = ExecManifest.runtimes(mf, rmc).get - runtimes.resolveDefaultRuntime("i1").get.image.publicImageName shouldBe "pre/???:test" - runtimes.resolveDefaultRuntime("i2").get.image.publicImageName shouldBe "ppp/???:test" + runtimes.resolveDefaultRuntime("i1").get.image.publicImageName shouldBe "???" + runtimes.resolveDefaultRuntime("i2").get.image.publicImageName shouldBe "ppp/???" runtimes.resolveDefaultRuntime("j1").get.image.publicImageName shouldBe "ppp/???:ttt" - runtimes.resolveDefaultRuntime("k1").get.image.publicImageName shouldBe "pre/???:ttt" - runtimes.resolveDefaultRuntime("s1").get.image.publicImageName shouldBe "pre/???:test" + runtimes.resolveDefaultRuntime("k1").get.image.publicImageName shouldBe "???:ttt" + runtimes.resolveDefaultRuntime("s1").get.image.publicImageName shouldBe "???" runtimes.resolveDefaultRuntime("s1").get.stemCells.get(0).count shouldBe 2 runtimes.resolveDefaultRuntime("s1").get.stemCells.get(0).memory shouldBe 256.MB } @@ -126,27 +126,25 @@ class ExecManifestTests extends FlatSpec with WskActorSystem with StreamLogging runtimes.skipDockerPull(ImageName("???", Some("bbb"))) shouldBe false } - it should "read a valid configuration with blackbox images, default prefix and tag" in { - val imgs = Set( + it should "read a valid configuration with blackbox images, which may omit prefix or tag" in { + val imgs = List( ImageName("???"), ImageName("???", Some("ppp")), ImageName("???", Some("ppp"), Some("ttt")), ImageName("???", None, Some("ttt"))) val mf = JsObject("runtimes" -> JsObject(), "blackboxes" -> imgs.toJson) - val rmc = RuntimeManifestConfig(defaultImagePrefix = Some("pre"), defaultImageTag = Some("test")) + val rmc = RuntimeManifestConfig() val runtimes = ExecManifest.runtimes(mf, rmc).get - runtimes.blackboxImages shouldBe { - Set( - ImageName("???", Some("pre"), Some("test")), - ImageName("???", Some("ppp"), Some("test")), - ImageName("???", Some("ppp"), Some("ttt")), - ImageName("???", Some("pre"), Some("ttt"))) - } + runtimes.blackboxImages shouldBe imgs.toSet + + imgs.forall(runtimes.skipDockerPull(_)) shouldBe true - runtimes.skipDockerPull(ImageName("???", Some("pre"), Some("test"))) shouldBe true - runtimes.skipDockerPull(ImageName("???", Some("bbb"), Some("test"))) shouldBe false + runtimes.skipDockerPull(ImageName("xxx")) shouldBe false + runtimes.skipDockerPull(ImageName("???", Some("bbb"))) shouldBe false + runtimes.skipDockerPull(ImageName("???", Some("ppp"), Some("test"))) shouldBe false + runtimes.skipDockerPull(ImageName("???", None, Some("test"))) shouldBe false } it should "reject runtimes with multiple defaults" in { @@ -171,17 +169,15 @@ class ExecManifestTests extends FlatSpec with WskActorSystem with StreamLogging Seq( (ExecManifest.ImageName(name), name), - (ExecManifest.ImageName(name, Some("pre")), s"pre/$name"), (ExecManifest.ImageName(name, None, Some("t")), s"$name:t"), + (ExecManifest.ImageName(name, Some("pre")), s"pre/$name"), (ExecManifest.ImageName(name, Some("pre"), Some("t")), s"pre/$name:t")).foreach { case (image, exp) => image.publicImageName shouldBe exp + image.localImageName("") shouldBe exp + image.localImageName("r") shouldBe s"r/$exp" + image.localImageName("r/") shouldBe s"r/$exp" - image.localImageName("", "", None) shouldBe image.tag.map(t => s"$name:$t").getOrElse(s"$name:latest") - image.localImageName("", "p", None) shouldBe image.tag.map(t => s"p/$name:$t").getOrElse(s"p/$name:latest") - image.localImageName("r", "", None) shouldBe image.tag.map(t => s"r/$name:$t").getOrElse(s"r/$name:latest") - image.localImageName("r", "p", None) shouldBe image.tag.map(t => s"r/p/$name:$t").getOrElse(s"r/p/$name:latest") - image.localImageName("r", "p", Some("tag")) shouldBe s"r/p/$name:tag" } }