Add a namespace configuration option to KCF (#4712)

Enables configuring the k8s namespace which would be used for creating the pod for actions. By default the action pods are launched in same namespace as the Invoker. Now one can specify a different namespace via `action-namespace` config setting

Fixes #4711
diff --git a/core/invoker/src/main/resources/application.conf b/core/invoker/src/main/resources/application.conf
index b518756..0f59dd6 100644
--- a/core/invoker/src/main/resources/application.conf
+++ b/core/invoker/src/main/resources/application.conf
@@ -77,7 +77,6 @@
       key: "openwhisk-role"
       value: "invoker"
     }
-
     # Enables forwarding to remote port via a local random port. This mode is mostly useful
     # for development via Standalone mode
     port-forwarding-enabled = false
@@ -87,6 +86,12 @@
     #  2. OR yaml formatted multi line string. See multi line config support https://github.com/lightbend/config/blob/master/HOCON.md#multi-line-strings
     #
     #pod-template =
+
+    # Set this optional string to be the namespace that the invoker should target for adding pods. This allows the invoker to run in a namesapce it doesn't have API access to but add pods to another namespace. See also https://github.com/apache/openwhisk/issues/4711
+    # When not set the underlying client may pickup the namesapce from the kubeconfig or via system property setting.
+    # See https://github.com/fabric8io/kubernetes-client#configuring-the-client for more information.
+    # action-namespace = "ns-actions"
+
   }
 
   # Timeouts for runc commands. Set to "Inf" to disable timeout.
diff --git a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/kubernetes/KubernetesClient.scala b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/kubernetes/KubernetesClient.scala
index 87a9a59..cae0062 100644
--- a/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/kubernetes/KubernetesClient.scala
+++ b/core/invoker/src/main/scala/org/apache/openwhisk/core/containerpool/kubernetes/KubernetesClient.scala
@@ -76,6 +76,7 @@
                                   invokerAgent: KubernetesInvokerAgentConfig,
                                   userPodNodeAffinity: KubernetesInvokerNodeAffinity,
                                   portForwardingEnabled: Boolean,
+                                  actionNamespace: Option[String] = None,
                                   podTemplate: Option[ConfigMapValue] = None)
 
 /**
@@ -93,11 +94,13 @@
     with ProcessRunner {
   implicit protected val ec = executionContext
   implicit protected val am = ActorMaterializer()
-  implicit protected val kubeRestClient = new DefaultKubernetesClient(
-    new ConfigBuilder()
+  implicit protected val kubeRestClient = {
+    val configBuilder = new ConfigBuilder()
       .withConnectionTimeout(config.timeouts.logs.toMillis.toInt)
       .withRequestTimeout(config.timeouts.logs.toMillis.toInt)
-      .build())
+    config.actionNamespace.foreach(configBuilder.withNamespace)
+    new DefaultKubernetesClient(configBuilder.build())
+  }
 
   private val podBuilder = new WhiskPodBuilder(kubeRestClient, config.userPodNodeAffinity, config.podTemplate)