This is an automated email from the ASF dual-hosted git repository.
slange 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 19a1981 additional container factory dns configuration (#4176)
19a1981 is described below
commit 19a19810f35c503d1125fcff5fd7885aa199cd2b
Author: David Grove <[email protected]>
AuthorDate: Thu Jan 17 11:31:08 2019 -0500
additional container factory dns configuration (#4176)
Allow configuration of the --dns-search and --dns-opt (--dns-option)
arguments to the docker run command of the DockerContainerFactory.
Motivated by better support of event providers in Kubernetes when
using the DockerContainerFactory.
---
.../core/containerpool/ContainerFactory.scala | 2 ++
core/invoker/src/main/resources/application.conf | 4 ++++
.../core/containerpool/docker/DockerClient.scala | 24 +++++++++++++++++++++-
.../containerpool/docker/DockerContainer.scala | 6 ++++++
.../docker/DockerContainerFactory.scala | 2 ++
.../docker/test/DockerClientTests.scala | 3 +++
.../test/DockerClientWithFileAccessTests.scala | 2 ++
.../docker/test/DockerContainerFactoryTests.scala | 6 +++++-
.../docker/test/DockerContainerTests.scala | 2 ++
.../mesos/test/MesosContainerFactoryTest.scala | 14 +++++++++++--
.../test/ContainerArgsConfigTest.scala | 10 +++++++++
11 files changed, 71 insertions(+), 4 deletions(-)
diff --git
a/common/scala/src/main/scala/org/apache/openwhisk/core/containerpool/ContainerFactory.scala
b/common/scala/src/main/scala/org/apache/openwhisk/core/containerpool/ContainerFactory.scala
index ce68010..ad78ce2 100644
---
a/common/scala/src/main/scala/org/apache/openwhisk/core/containerpool/ContainerFactory.scala
+++
b/common/scala/src/main/scala/org/apache/openwhisk/core/containerpool/ContainerFactory.scala
@@ -27,6 +27,8 @@ import scala.concurrent.Future
case class ContainerArgsConfig(network: String,
dnsServers: Seq[String] = Seq.empty,
+ dnsSearch: Seq[String] = Seq.empty,
+ dnsOptions: Seq[String] = Seq.empty,
extraArgs: Map[String, Set[String]] = Map.empty)
case class ContainerPoolConfig(userMemory: ByteSize, concurrentPeekFactor:
Double, akkaClient: Boolean) {
diff --git a/core/invoker/src/main/resources/application.conf
b/core/invoker/src/main/resources/application.conf
index 3efdf15..c1d4bf7 100644
--- a/core/invoker/src/main/resources/application.conf
+++ b/core/invoker/src/main/resources/application.conf
@@ -28,6 +28,7 @@ whisk {
inspect: 1 minute
pause: 10 seconds
unpause: 10 seconds
+ version: 10 seconds
}
}
@@ -68,7 +69,10 @@ whisk {
# args for 'docker run' to use
container-factory.container-args {
network: bridge
+ # See
https://docs.docker.com/config/containers/container-networking/#dns-services
for documentation of dns-*
dns-servers: []
+ dns-search: []
+ dns-options: []
extra-args: {} # to pass additional args to 'docker run'; format is
`{key1: [v1, v2], key2: [v1, v2]}`
}
diff --git
a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerClient.scala
b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerClient.scala
index 355c3ab..db42d93 100644
---
a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerClient.scala
+++
b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerClient.scala
@@ -27,7 +27,7 @@ import akka.actor.ActorSystem
import scala.collection.concurrent.TrieMap
import scala.concurrent.blocking
import scala.concurrent.ExecutionContext
-import scala.concurrent.Future
+import scala.concurrent.{Await, Future}
import scala.util.Failure
import scala.util.Success
import scala.util.Try
@@ -61,6 +61,7 @@ case class DockerClientTimeoutConfig(run: Duration,
ps: Duration,
pause: Duration,
unpause: Duration,
+ version: Duration,
inspect: Duration)
/**
@@ -98,6 +99,20 @@ class DockerClient(dockerHost: Option[String] = None,
Seq(dockerBin) ++ host
}
+ // Invoke docker CLI to determine client version.
+ // If the docker client version cannot be determined, an exception will be
thrown and instance initialization will fail.
+ // Rationale: if we cannot invoke `docker version` successfully, it is
unlikely subsequent `docker` invocations will succeed.
+ protected def getClientVersion(): String = {
+ val vf = executeProcess(dockerCmd ++ Seq("version", "--format",
"{{.Client.Version}}"), config.timeouts.version)
+ .andThen {
+ case Success(version) => log.info(this, s"Detected docker client
version $version")
+ case Failure(e) =>
+ log.error(this, s"Failed to determine docker client version:
${e.getClass} - ${e.getMessage}")
+ }
+ Await.result(vf, 2 * config.timeouts.version)
+ }
+ val clientVersion: String = getClientVersion()
+
protected val maxParallelRuns = config.parallelRuns
protected val runSemaphore =
new Semaphore( /* permits= */ if (maxParallelRuns > 0) maxParallelRuns
else Int.MaxValue, /* fair= */ true)
@@ -198,6 +213,13 @@ class DockerClient(dockerHost: Option[String] = None,
trait DockerApi {
/**
+ * The version number of the docker client cli
+ *
+ * @return The version of the docker client cli being used by the invoker
+ */
+ def clientVersion: String
+
+ /**
* Spawns a container in detached mode.
*
* @param image the image to start the container with
diff --git
a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainer.scala
b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainer.scala
index b8b4057..7ac95e4 100644
---
a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainer.scala
+++
b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainer.scala
@@ -65,6 +65,8 @@ object DockerContainer {
environment: Map[String, String] = Map.empty,
network: String = "bridge",
dnsServers: Seq[String] = Seq.empty,
+ dnsSearch: Seq[String] = Seq.empty,
+ dnsOptions: Seq[String] = Seq.empty,
name: Option[String] = None,
useRunc: Boolean = true,
dockerRunParameters: Map[String, Set[String]])(implicit docker:
DockerApiWithFileAccess,
@@ -82,6 +84,8 @@ object DockerContainer {
case (key, valueList) => valueList.toList.flatMap(Seq(key, _))
}
+ // NOTE: --dns-option on modern versions of docker, but is --dns-opt on
docker 1.12
+ val dnsOptString = if (docker.clientVersion.startsWith("1.12")) {
"--dns-opt" } else { "--dns-option" }
val args = Seq(
"--cpu-shares",
cpuShares.toString,
@@ -93,6 +97,8 @@ object DockerContainer {
network) ++
environmentArgs ++
dnsServers.flatMap(d => Seq("--dns", d)) ++
+ dnsSearch.flatMap(d => Seq("--dns-search", d)) ++
+ dnsOptions.flatMap(d => Seq(dnsOptString, d)) ++
name.map(n => Seq("--name", n)).getOrElse(Seq.empty) ++
params
diff --git
a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainerFactory.scala
b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainerFactory.scala
index c4ceff3..0fad560 100644
---
a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainerFactory.scala
+++
b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/docker/DockerContainerFactory.scala
@@ -69,6 +69,8 @@ class DockerContainerFactory(instance: InvokerInstanceId,
environment = Map("__OW_API_HOST" -> config.wskApiHost),
network = containerArgsConfig.network,
dnsServers = containerArgsConfig.dnsServers,
+ dnsSearch = containerArgsConfig.dnsSearch,
+ dnsOptions = containerArgsConfig.dnsOptions,
name = Some(name),
useRunc = dockerContainerFactoryConfig.useRunc,
parameters ++ containerArgsConfig.extraArgs.map { case (k, v) => ("--" +
k, v) })
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientTests.scala
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientTests.scala
index 1633a02..7de2a35 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientTests.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientTests.scala
@@ -67,6 +67,7 @@ class DockerClientTests
/** Returns a DockerClient with a mocked result for 'executeProcess' */
def dockerClient(execResult: => Future[String]) = new DockerClient()(global)
{
override val dockerCmd = Seq(dockerCommand)
+ override def getClientVersion() = "mock-test-client"
override def executeProcess(args: Seq[String], timeout: Duration)(implicit
ec: ExecutionContext, as: ActorSystem) =
execResult
}
@@ -189,6 +190,7 @@ class DockerClientTests
var runCmdCount = 0
val dc = new DockerClient()(global) {
override val dockerCmd = Seq(dockerCommand)
+ override def getClientVersion() = "mock-test-client"
override def executeProcess(args: Seq[String], timeout:
Duration)(implicit ec: ExecutionContext,
as:
ActorSystem) = {
runCmdCount += 1
@@ -237,6 +239,7 @@ class DockerClientTests
var runCmdCount = 0
val dc = new DockerClient()(global) {
override val dockerCmd = Seq(dockerCommand)
+ override def getClientVersion() = "mock-test-client"
override def executeProcess(args: Seq[String], timeout:
Duration)(implicit ec: ExecutionContext,
as:
ActorSystem) = {
runCmdCount += 1
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientWithFileAccessTests.scala
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientWithFileAccessTests.scala
index a3936ac..f21063d 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientWithFileAccessTests.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerClientWithFileAccessTests.scala
@@ -73,6 +73,7 @@ class DockerClientWithFileAccessTestsIp
readResult: Future[JsObject] =
Future.successful(dockerConfig)) =
new DockerClientWithFileAccess()(global) {
override val dockerCmd = Seq(dockerCommand)
+ override def getClientVersion() = "mock-test-client"
override def executeProcess(args: Seq[String], timeout:
Duration)(implicit ec: ExecutionContext,
as:
ActorSystem) = execResult
override def configFileContents(configFile: File) = readResult
@@ -129,6 +130,7 @@ class DockerClientWithFileAccessTestsOom
def dockerClient(readResult: Future[JsObject]) =
new DockerClientWithFileAccess()(global) {
override val dockerCmd = Seq("docker")
+ override def getClientVersion() = "mock-test-client"
override def configFileContents(configFile: File) = readResult
}
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala
index 80b400d..212de56 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerFactoryTests.scala
@@ -102,12 +102,16 @@ class DockerContainerFactoryTests
.rm(_: ContainerId)(_: TransactionId))
.expects(ContainerId("fakecontainerid"), *)
.returning(Future.successful(Unit))
+ //setup clientVersion exceptation
+ (dockerApiStub.clientVersion _)
+ .expects()
+ .returning("mock_test_client")
val factory =
new DockerContainerFactory(
InvokerInstanceId(0, userMemory = defaultUserMemory),
Map.empty,
- ContainerArgsConfig("net1", Seq("dns1", "dns2"), Map("env" ->
Set("e1", "e2"))),
+ ContainerArgsConfig("net1", Seq("dns1", "dns2"), Seq.empty, Seq.empty,
Map("env" -> Set("e1", "e2"))),
DockerContainerFactoryConfig(true))(actorSystem, executionContext,
logging, dockerApiStub, mock[RuncApi])
val cf = factory.createContainer(tid, "testContainer", image, false,
10.MB, 32)
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerTests.scala
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerTests.scala
index e1253a1..5edef3c 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerTests.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/docker/test/DockerContainerTests.scala
@@ -807,6 +807,8 @@ class DockerContainerTests
var pulls = mutable.Buffer.empty[String]
var rawContainerLogsInvocations = mutable.Buffer.empty[(ContainerId, Long,
Option[FiniteDuration])]
+ def clientVersion: String = "mock-test-client"
+
def run(image: String, args: Seq[String] = Seq.empty[String])(
implicit transid: TransactionId): Future[ContainerId] = {
runs += ((image, args))
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala
index 0178bc8..225a79b 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/mesos/test/MesosContainerFactoryTest.scala
@@ -86,7 +86,12 @@ class MesosContainerFactoryTest
val mesosCpus = poolConfig.cpuShare(actionMemory) / 1024.0
val containerArgsConfig =
- new ContainerArgsConfig("net1", Seq("dns1", "dns2"), Map("extra1" ->
Set("e1", "e2"), "extra2" -> Set("e3", "e4")))
+ new ContainerArgsConfig(
+ "net1",
+ Seq("dns1", "dns2"),
+ Seq.empty,
+ Seq.empty,
+ Map("extra1" -> Set("e1", "e2"), "extra2" -> Set("e3", "e4")))
override def beforeEach() = {
stream.reset()
@@ -247,7 +252,12 @@ class MesosContainerFactoryTest
system,
logging,
Map("--arg1" -> Set("v1", "v2"), "--arg2" -> Set("v3", "v4"), "other"
-> Set("v5", "v6")),
- new ContainerArgsConfig("bridge", Seq.empty, Map("extra1" -> Set("e1",
"e2"), "extra2" -> Set("e3", "e4"))),
+ new ContainerArgsConfig(
+ "bridge",
+ Seq.empty,
+ Seq.empty,
+ Seq.empty,
+ Map("extra1" -> Set("e1", "e2"), "extra2" -> Set("e3", "e4"))),
mesosConfig,
(system, mesosConfig) => probe.testActor,
testTaskId _)
diff --git
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/test/ContainerArgsConfigTest.scala
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/test/ContainerArgsConfigTest.scala
index 7edd3e8..40add24 100644
---
a/tests/src/test/scala/org/apache/openwhisk/core/containerpool/test/ContainerArgsConfigTest.scala
+++
b/tests/src/test/scala/org/apache/openwhisk/core/containerpool/test/ContainerArgsConfigTest.scala
@@ -34,6 +34,8 @@ class ContainerArgsConfigTest extends FlatSpec with Matchers {
//check defaults
config.network shouldBe "bridge"
config.dnsServers shouldBe Seq[String]()
+ config.dnsSearch shouldBe Seq[String]()
+ config.dnsOptions shouldBe Seq[String]()
config.extraArgs shouldBe Map[String, Set[String]]()
}
@@ -46,10 +48,18 @@ class ContainerArgsConfigTest extends FlatSpec with
Matchers {
System.setProperty("whisk.container-factory.container-args.dns-servers.0",
"google.com")
System.setProperty("whisk.container-factory.container-args.dns-servers.1",
"1.2.3.4")
+
+ System.setProperty("whisk.container-factory.container-args.dns-search.0",
"a.b.c")
+ System.setProperty("whisk.container-factory.container-args.dns-search.1",
"a.b")
+
+ System.setProperty("whisk.container-factory.container-args.dns-options.0",
"ndots:5")
+
val config =
loadConfigOrThrow[ContainerArgsConfig](ConfigKeys.containerArgs)
//check defaults
config.network shouldBe "bridge"
config.dnsServers shouldBe Seq[String]("google.com", "1.2.3.4")
+ config.dnsSearch shouldBe Seq[String]("a.b.c", "a.b")
+ config.dnsOptions shouldBe Seq[String]("ndots:5")
//check map parsing of extra-args config
config.extraArgs.get("label") shouldBe Some(Set("l1", "l2", "l3"))
config.extraArgs.get("env") shouldBe Some(Set("e1", "e2"))