summaryrefslogtreecommitdiffstats
path: root/multisite-init-container
diff options
context:
space:
mode:
Diffstat (limited to 'multisite-init-container')
-rw-r--r--multisite-init-container/Dockerfile22
-rw-r--r--multisite-init-container/README.md33
-rw-r--r--multisite-init-container/buildconf.py82
-rw-r--r--multisite-init-container/pom.xml172
4 files changed, 309 insertions, 0 deletions
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>