Set up kubeconfig ConfigMap

Add container to update configMap with info for central cluster.
Update Cloudify Manager version.

Issue-ID: DCAEGEN2-1136
Issue-ID: DCAEGEN2-1376
Change-Id: I593703b25c2ec9c8fde6ca10c9fc70255c6719a5
Signed-off-by: Jack Lucas <jflucas@research.att.com>
diff --git a/cm-container/Dockerfile-template b/cm-container/Dockerfile-template
index 8524ee8..fbf6ca8 100644
--- a/cm-container/Dockerfile-template
+++ b/cm-container/Dockerfile-template
@@ -17,7 +17,7 @@
 # ============LICENSE_END=========================================================
 #
 # ECOMP is a trademark and service mark of AT&T Intellectual Property.
-FROM cloudifyplatform/community:18.7.23
+FROM cloudifyplatform/community:19.01.24
 MAINTAINER maintainer
 
 ENV TYPE_REPO {{ ONAPTEMPLATE_RAWREPOURL_org_onap_dcaegen2_platform_plugins_releases }}
diff --git a/cm-container/pom.xml b/cm-container/pom.xml
index 4cac26d..21cf722 100644
--- a/cm-container/pom.xml
+++ b/cm-container/pom.xml
@@ -27,7 +27,7 @@
   <groupId>org.onap.dcaegen2.deployments</groupId>
   <artifactId>cm-container</artifactId>
   <name>dcaegen2-deployments-cm-container</name>
-  <version>1.5.2</version>
+  <version>1.6.0</version>
   <url>http://maven.apache.org</url>
   <properties>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
diff --git a/multisite-init-container/Dockerfile b/multisite-init-container/Dockerfile
new file mode 100644
index 0000000..9052b92
--- /dev/null
+++ b/multisite-init-container/Dockerfile
@@ -0,0 +1,22 @@
+# ================================================================================
+# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+#
+FROM python:3-alpine
+RUN mkdir /opt/onap
+RUN pip install kubernetes
+COPY buildconf.py /opt/onap
+WORKDIR /opt/onap
+ENTRYPOINT ["python3", "/opt/onap/buildconf.py"]
\ No newline at end of file
diff --git a/multisite-init-container/README.md b/multisite-init-container/README.md
new file mode 100644
index 0000000..ce4a0ed
--- /dev/null
+++ b/multisite-init-container/README.md
@@ -0,0 +1,33 @@
+# Multisite Initialization Container
+This container sets up the initial entry in a kubeconfig file that
+Cloudify Manager (and potentially other components) can use to access
+multiple Kubernetes clusters.   The initial entry is for the central
+site.
+
+The container runs a short Python script to completion.  It's meant to be
+run as an init container or as a standalone Kubernetes Job. (In the R4 ["Dublin"] release, it's
+run as an init container for the Cloudify Manager pod.)   The script works by
+using the Kubernetes API to get three pieces of information about the cluster where the script is running:
+  1. the address of the Kubernetes API server
+  2. the CA certificate for the server
+  3. an authorization token that can be presented with each API request.
+
+The script combines this information with other values provided from command line arguments and/or defaults
+to create a kubeconfig-style structure that it uses to update an existing Kubernetes ConfigMap.  (It uses an
+existing ConfigMap, rather than creating a new one, in order to work well with the OOM Helm deployment
+strategy.  The OOM Helm charts create an empty ConfigMap, so that Helm knows about the ConfigMap and can delete
+it cleanly when uninstalling.  If the script created a new ConfigMap,
+Helm would not know about it and would not delete it during an uninstall
+operation.)
+
+The table below shows the command line arguments that can be passed to the script via the "args" array in the
+Kubernetes spec for the container.
+| Argument | Description | Required? | Default
+|----------|-------|-----------|--------
+|--namespace, -n | Namespace where CM will run | Yes | None
+|--location, -l  | Name of the central location | No | "central"
+|--user, -u | User name for authorization | No | "user00"
+|--configmap, -c | Name of the ConfigMap where the kubeconfig is stored | No | "multisite-kubeconfig-configmap"
+|--key, -k | Key under which the kubeconfig is stored (when mounted on a container, this will be file name)| No | "kubeconfig"
+
+
diff --git a/multisite-init-container/buildconf.py b/multisite-init-container/buildconf.py
new file mode 100644
index 0000000..774f407
--- /dev/null
+++ b/multisite-init-container/buildconf.py
@@ -0,0 +1,82 @@
+# ================================================================================
+# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+# ================================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ============LICENSE_END=========================================================
+#
+# Extract the API address and credentials provided
+# to the container by Kubernetes and push it into a
+# configmap that can be shared by other components
+# and that can be augmented with addresses and credentials
+# of remote Kubernetes clusters.
+
+from kubernetes import client, config
+import yaml
+import string
+import base64
+
+# Default values for parameters
+K8S_CENTRAL_LOCATION_ID = "central"                 # Used as cluster and context name in kubeconfig
+K8S_USER = "user00"                                 # Used as user name in kubeconfig
+CONFIG_MAP_NAME = "multisite-kubeconfig-configmap"    # Name of the existing ConfigMap that receives the kubeconfig
+CONFIG_MAP_KEY = "kubeconfig"                       # Key in ConfigMap where kubeconfig is stored
+
+def _get_config():
+    ''' Get API access configuration as provided by k8s '''
+    config.load_incluster_config()
+    cfg = client.Configuration._default
+
+    token = cfg.api_key['authorization'].split(' ')[1]
+    server = cfg.host
+    with open(cfg.ssl_ca_cert, 'r') as f:
+        ca_cert = f.read().strip()
+
+    ca_cert_string = base64.standard_b64encode(ca_cert.encode('utf-8'))
+
+    return token, server, ca_cert_string
+
+def _build_kubeconfig(location, kuser):
+    ''' Build content of a kubeconfig file using the access info provided by k8s '''
+
+    token, server, ca_cert = _get_config()
+    cluster = {"name": location, "cluster": {"server": server, "certificate-authority-data": ca_cert}}
+    user = {"name": kuser, "user": {"token": token}}
+    context = {"name": location, "context": {"cluster": location, "user": kuser}}
+
+    kubeconfig = {"apiVersion": "v1", "kind": "Config", "preferences": {}, "current-context": location}
+    kubeconfig["clusters"] = [cluster]
+    kubeconfig["users"] = [user]
+    kubeconfig["contexts"] = [context]
+
+    return kubeconfig
+
+def update_kubeconfig_config_map(namespace, config_map_name, key, kubeconfig):
+    body = client.V1ConfigMap(data={key: yaml.safe_dump(kubeconfig)})
+    client.CoreV1Api().patch_namespaced_config_map(config_map_name, namespace, body)
+
+def create_kubeconfig_file(location, user, config_file):
+    ''' Write a kubeconfig file using the API access info provided by k8s '''
+    with open(config_file, 'w') as f:
+        yaml.safe_dump(_build_kubeconfig(location, user), f)
+
+if __name__ == "__main__":
+    from optparse import OptionParser
+    parser = OptionParser()
+    parser.add_option("-l", "--location", dest="location", help="Name of central location", default=K8S_CENTRAL_LOCATION_ID)
+    parser.add_option("-u", "--user", dest="user", help="Username", default=K8S_USER)
+    parser.add_option("-n", "--namespace", dest="namespace", help="Target namespace")
+    parser.add_option("-c", "--configmap", dest="configmap", help= "ConfigMap name", default=CONFIG_MAP_NAME)
+    parser.add_option("-k", "--key", dest="key", help="ConfigMap key (filename when ConfigMap is mounted)", default=CONFIG_MAP_KEY)
+    (options, args) = parser.parse_args()
+    kubeconfig = _build_kubeconfig(options.location, options.user)
+    update_kubeconfig_config_map(options.namespace,options.configmap,options.key, kubeconfig)
\ No newline at end of file
diff --git a/multisite-init-container/pom.xml b/multisite-init-container/pom.xml
new file mode 100644
index 0000000..dac523b
--- /dev/null
+++ b/multisite-init-container/pom.xml
@@ -0,0 +1,172 @@
+<?xml version="1.0"?>
+<!--
+================================================================================
+Copyright (c) 2018-2019 AT&T Intellectual Property. All rights reserved.
+================================================================================
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+============LICENSE_END=========================================================
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.onap.dcaegen2.deployments</groupId>
+    <artifactId>deployments</artifactId>
+    <version>1.2.0-SNAPSHOT</version>
+  </parent>
+  <groupId>org.onap.dcaegen2.deployments</groupId>
+  <artifactId>multisite-init-container</artifactId>
+  <name>dcaegen2-deployments-multisite-init-container</name>
+  <version>1.0.0</version>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <sonar.skip>true</sonar.skip>
+    <sonar.sources>.</sonar.sources>
+    <!-- customize the SONARQUBE URL -->
+    <!-- sonar.host.url>http://localhost:9000</sonar.host.url -->
+    <!-- below are language dependent -->
+    <!-- for Python -->
+    <sonar.language>py</sonar.language>
+    <sonar.pluginName>Python</sonar.pluginName>
+    <sonar.inclusions>**/*.py</sonar.inclusions>
+    <!-- for JavaScaript -->
+    <!--
+    <sonar.language>js</sonar.language>
+    <sonar.pluginName>JS</sonar.pluginName>
+    <sonar.inclusions>**/*.js</sonar.inclusions>
+    -->
+  </properties>
+  <build>
+    <finalName>${project.artifactId}-${project.version}</finalName>
+    <plugins>
+      <!-- plugin>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>2.4.1</version>
+        <configuration>
+          <descriptors>
+            <descriptor>assembly/dep.xml</descriptor>
+          </descriptors>
+        </configuration>
+        <executions>
+          <execution>
+            <id>make-assembly</id>
+            <phase>package</phase>
+            <goals>
+              <goal>single</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin -->
+      <!-- now we configure custom action (calling a script) at various lifecycle phases -->
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>exec-maven-plugin</artifactId>
+        <version>1.2.1</version>
+        <executions>
+          <execution>
+            <id>clean phase script</id>
+            <phase>clean</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>clean</argument>
+              </arguments>
+            </configuration>
+          </execution>
+          <execution>
+            <id>generate-sources script</id>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>generate-sources</argument>
+              </arguments>
+            </configuration>
+          </execution>
+          <execution>
+            <id>compile script</id>
+            <phase>compile</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>compile</argument>
+              </arguments>
+            </configuration>
+          </execution>
+          <execution>
+            <id>package script</id>
+            <phase>package</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>package</argument>
+              </arguments>
+            </configuration>
+          </execution>
+          <execution>
+            <id>test script</id>
+            <phase>test</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>test</argument>
+              </arguments>
+            </configuration>
+          </execution>
+          <execution>
+            <id>install script</id>
+            <phase>install</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>install</argument>
+              </arguments>
+            </configuration>
+          </execution>
+          <execution>
+            <id>deploy script</id>
+            <phase>deploy</phase>
+            <goals>
+              <goal>exec</goal>
+            </goals>
+            <configuration>
+              <arguments>
+                <argument>${project.artifactId}</argument>
+                <argument>deploy</argument>
+              </arguments>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+</project>
diff --git a/pom.xml b/pom.xml
index f05745d..ee0e322 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,7 @@
      <module>healthcheck-container</module>
      <module>tls-init-container</module>
      <module>consul-loader-container</module>
+     <module>multisite-init-container</module>
   </modules>
   <profiles>
     <profile>