summaryrefslogtreecommitdiffstats
path: root/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common
diff options
context:
space:
mode:
Diffstat (limited to 'cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common')
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/__init__.py14
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/constants.py20
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/deployment_result.py27
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/helm.py62
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/init_pod.py63
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/namespace.py101
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/resources_services.py230
-rw-r--r--cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/workarounds.py67
8 files changed, 584 insertions, 0 deletions
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/__init__.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/__init__.py
new file mode 100644
index 0000000000..19a30ba43d
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/__init__.py
@@ -0,0 +1,14 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/constants.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/constants.py
new file mode 100644
index 0000000000..493a44f16f
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/constants.py
@@ -0,0 +1,20 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+HELM_URL = 'https://kubernetes-helm.storage.googleapis.com/helm-canary-linux-amd64.tar.gz'
+OOM_GIT_URL = 'https://gerrit.onap.org/r/oom.git'
+
+RT_HELM_CLI_PATH = "helm_cli_path"
+RT_APPS_ROOT_PATH = "app_root_path"
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/deployment_result.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/deployment_result.py
new file mode 100644
index 0000000000..48d49e0403
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/deployment_result.py
@@ -0,0 +1,27 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+from cloudify import ctx
+
+
+def save_deployment_result(key):
+ result = ctx.instance.runtime_properties['kubernetes']
+ ctx.instance.runtime_properties[key] = result
+ ctx.instance.runtime_properties['kubernetes'] = {}
+
+
+def set_deployment_result(key):
+ result = ctx.instance.runtime_properties.pop(key)
+ ctx.instance.runtime_properties['kubernetes'] = result \ No newline at end of file
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/helm.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/helm.py
new file mode 100644
index 0000000000..4404f6f832
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/helm.py
@@ -0,0 +1,62 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+import urllib
+import tarfile
+import os
+import tempfile
+from git import Repo
+
+def get_helm_path(url):
+ tarball = _fetch_helm(url)
+ helm_dir = _get_tmp_file_name()
+ _untar_helm_archive(tarball, helm_dir)
+ helm_binary_path = _find_file('helm', helm_dir)
+ return helm_binary_path
+
+
+def get_apps_root_path(git_url):
+ dst_repo_path = _get_tmp_file_name()
+ Repo.clone_from(git_url, dst_repo_path)
+ apps_root = format(dst_repo_path)
+ return apps_root
+
+def _fetch_helm(url):
+ dst_tar_path = _get_tmp_file_name()
+
+ file = urllib.URLopener()
+ file.retrieve(url, dst_tar_path)
+
+ return dst_tar_path
+
+def _untar_helm_archive(tar_path, helm_dir):
+ helm_tar = tarfile.open(tar_path)
+ helm_tar.extractall(helm_dir)
+ helm_tar.close()
+
+
+def _find_file(filename, base_path):
+ for root, dirs, files in os.walk(base_path):
+ for name in files:
+ if name == filename:
+ return os.path.abspath(os.path.join(root, name))
+
+ raise Exception('Cannot find helm binary')
+
+
+def _get_tmp_file_name():
+ return '{}/{}'.format(tempfile._get_default_tempdir(), next(tempfile._get_candidate_names()))
+
+
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/init_pod.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/init_pod.py
new file mode 100644
index 0000000000..1376818b7b
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/init_pod.py
@@ -0,0 +1,63 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+from cloudify import ctx
+import yaml
+
+import constants
+import resources_services
+
+SERVICES_FILE_PARTS_SEPARATOR = '---'
+
+
+def do_create_init_pod():
+ ctx.logger.info('Creating init pod')
+
+ yaml_config = resources_services.render_chart(
+ ctx.node.properties["init_pod"],
+ _retrieve_root_path(),
+ _retrieve_helm_cli_path()
+ )
+ yaml_content_part = yaml_config.split(SERVICES_FILE_PARTS_SEPARATOR)[2]
+ enhanced_yaml = _add_openstack_envs(yaml_content_part)
+
+ resources_services.create_resource(enhanced_yaml)
+
+ ctx.logger.info('Init pod created successfully')
+
+
+def do_delete_init_pod():
+ ctx.logger.info('Deleting init pod')
+
+ ctx.logger.info('Init pod deleted successfully')
+
+def _add_openstack_envs(yaml_content):
+ input_dict = yaml.load(yaml_content)
+
+ container_dict = input_dict['spec']['containers'][0]
+ container_dict.pop('envFrom')
+
+ openstack_envs = ctx.node.properties["openstack_envs"]
+ for item in openstack_envs.items():
+ ctx.logger.debug("adding item = {}".format(item))
+ container_dict['env'].append(item)
+
+ return input_dict
+
+def _retrieve_root_path():
+ return ctx.instance.runtime_properties.get(constants.RT_APPS_ROOT_PATH, None)
+
+def _retrieve_helm_cli_path():
+ return ctx.instance.runtime_properties.get(constants.RT_HELM_CLI_PATH, None) \ No newline at end of file
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/namespace.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/namespace.py
new file mode 100644
index 0000000000..d1336768ac
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/namespace.py
@@ -0,0 +1,101 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+import cloudify_kubernetes.tasks as kubernetes_plugin
+from cloudify import ctx
+from cloudify.exceptions import NonRecoverableError
+
+import deployment_result
+
+
+def do_create_namespace():
+ namespace = _retrieve_namespace()
+ ctx.logger.info('Creating namespace: {0}'.format(namespace))
+
+ namespace_resource_template = _prepare_namespace_resource_template(
+ namespace
+ )
+
+ ctx.logger.debug(
+ 'Kubernetes object which will be deployed: {0}'
+ .format(namespace_resource_template)
+ )
+
+ kubernetes_plugin.custom_resource_create(**namespace_resource_template)
+ deployment_result.save_deployment_result('namespace')
+ ctx.logger.info('Namespace created successfully')
+
+
+def do_delete_namespace():
+ namespace = _retrieve_namespace()
+ ctx.logger.info('Deleting namespace: {0}'.format(namespace))
+
+ namespace_resource_template = _prepare_namespace_resource_template(
+ namespace
+ )
+
+ ctx.logger.debug(
+ 'Kubernetes object which will be deleted: {0}'
+ .format(namespace_resource_template)
+ )
+
+ deployment_result.set_deployment_result('namespace')
+ kubernetes_plugin.custom_resource_delete(**namespace_resource_template)
+ ctx.logger.info('Namespace deleted successfully')
+
+
+
+def _retrieve_namespace():
+
+ default_namespace = ctx.node.properties.get('options', {}).get('namespace')
+ namespace = ctx.node.properties.get('namespace', default_namespace)
+
+ if not namespace:
+ raise NonRecoverableError(
+ 'Namespace is not defined (node={})'.format(ctx.node.name)
+ )
+
+ return namespace
+
+
+def _prepare_namespace_resource_template(name):
+ return {
+ 'definition': {
+ 'apiVersion': 'v1',
+ 'kind': 'Namespace',
+ 'metadata': {
+ 'name': name,
+ 'labels': {
+ 'name': name
+ },
+ },
+ },
+ 'api_mapping': {
+ 'create': {
+ 'api': 'CoreV1Api',
+ 'method': 'create_namespace',
+ 'payload': 'V1Namespace'
+ },
+ 'read': {
+ 'api': 'CoreV1Api',
+ 'method': 'read_namespace',
+ },
+ 'delete': {
+ 'api': 'CoreV1Api',
+ 'method': 'delete_namespace',
+ 'payload': 'V1DeleteOptions'
+ }
+ }
+ }
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/resources_services.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/resources_services.py
new file mode 100644
index 0000000000..268068f00c
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/resources_services.py
@@ -0,0 +1,230 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+import subprocess
+
+import cloudify_kubernetes.tasks as kubernetes_plugin
+import yaml
+from cloudify import ctx
+from cloudify.exceptions import NonRecoverableError
+
+import constants
+import deployment_result
+import time
+import ast
+import json
+import base64
+
+SERVICES_FILE_PARTS_SEPARATOR = '---'
+
+
+def create_resoruces():
+ ctx.logger.info('Creating resources')
+ apps_path = _retrieve_root_path()
+
+ if not apps_path:
+ ctx.logger.warn(
+ 'Apps dir is not defined. Skipping!'
+ )
+
+ return
+
+ helm_app = ctx.node.properties.get('path', None)
+
+ yaml_file = prepare_content(helm_app)
+
+ yaml_content_parts = yaml_file.split(SERVICES_FILE_PARTS_SEPARATOR)
+
+ for yaml_content_part in yaml_content_parts:
+ if yaml_content_part:
+ yaml_content = _apply_readiness_workaround(yaml_content_part)
+ if yaml_content:
+ create_resource(yaml_content)
+
+ ctx.logger.info('Resource created successfully')
+
+def delete_resoruces():
+
+ ctx.logger.info('Deleting resources')
+ apps_path = _retrieve_root_path()
+
+ if not apps_path:
+ ctx.logger.warn(
+ 'Apps dir is not defined. Skipping!'
+ )
+ return
+
+ helm_app = ctx.node.properties.get('path', None)
+
+ yaml_file = prepare_content(helm_app)
+
+ yaml_content_parts = yaml_file.split(SERVICES_FILE_PARTS_SEPARATOR)
+
+ for yaml_content_part in yaml_content_parts:
+ if yaml_content_part:
+ yaml_content = _apply_readiness_workaround(yaml_content_part)
+ if yaml_content:
+ delete_resource(yaml_content)
+
+ ctx.logger.info('Resources deleted successfully')
+
+
+def prepare_content(resource):
+ helm_path = _retrieve_helm_cli_path()
+ yaml_file = render_chart(resource, _retrieve_root_path(), helm_path)
+
+ return yaml_file
+
+
+def create_resource(yaml_content_dict):
+ ctx.logger.debug("Loading yaml: {}".format(yaml_content_dict))
+
+ if yaml_content_dict.get('kind', '') == 'PersistentVolumeClaim':
+ ctx.logger.debug("PersistentVolumeClaim custom handling")
+ kubernetes_plugin.custom_resource_create(definition=yaml_content_dict, api_mapping=_get_persistent_volume_mapping_claim_api())
+ else:
+ kubernetes_plugin.resource_create(definition=yaml_content_dict)
+
+ deployment_result.save_deployment_result('resource_{0}'.format(yaml_content_dict['metadata']['name']))
+
+def delete_resource(yaml_content_dict):
+ ctx.logger.debug("Loading yaml: {}".format(yaml_content_dict))
+
+ deployment_result.save_deployment_result('resource_{0}'.format(yaml_content_dict['metadata']['name']))
+ if yaml_content_dict.get('kind', '') == 'PersistentVolumeClaim':
+ ctx.logger.debug("PersistentVolumeClaim custom handling")
+ kubernetes_plugin.custom_resource_delete(definition=yaml_content_dict, api_mapping=_get_persistent_volume_mapping_claim_api())
+ else:
+ kubernetes_plugin.resource_delete(definition=yaml_content_dict)
+
+
+def render_chart(app, app_root_path, helm_cli_path):
+ app_chart_path = "{}/{}/".format(app_root_path, app)
+ ctx.logger.debug('App chart path = {}'.format(app_chart_path))
+ return _exec_helm_template(helm_cli_path, app_chart_path)
+
+
+def _exec_helm_template(helm_path, chart):
+ cmd = '{0} template {1}'.format(helm_path, chart)
+ ctx.logger.debug('Executing helm template cmd: {}'.format(cmd))
+ rendered = subprocess.Popen(cmd.split(" "), stdout=subprocess.PIPE).stdout.read().decode()
+
+ return rendered
+
+def _get_persistent_volume_mapping_claim_api():
+ api_mapping = {
+ 'create' : {
+ 'api': 'CoreV1Api',
+ 'method': 'create_namespaced_persistent_volume_claim',
+ 'payload': 'V1PersistentVolumeClaim'
+ },
+ 'read' : {
+ 'api': 'CoreV1Api',
+ 'method': 'read_namespaced_persistent_volume_claim',
+ },
+ 'delete': {
+ 'api': 'CoreV1Api',
+ 'method': 'delete_namespaced_persistent_volume_claim',
+ 'payload': 'V1DeleteOptions'
+ }
+ }
+
+ return api_mapping
+
+
+def _apply_readiness_workaround(yaml_file):
+ b64_env = _get_k8s_b64_env()
+
+ input_dict = yaml.load(yaml_file)
+
+ try:
+ init_containers = input_dict['spec']['template']['metadata']['annotations'][
+ 'pod.beta.kubernetes.io/init-containers']
+ init_cont_list = eval(init_containers)
+
+ new_init_cont_list = list()
+ new_cont = None
+ for init_cont in init_cont_list:
+ if "oomk8s/readiness-check" in init_cont['image']:
+ init_cont['image'] = "clfy/oomk8s-cfy-readiness-check:1.0.1"
+ #init_cont['imagePullPolicy'] = "IfNotPresent"
+ init_cont['env'].append(b64_env)
+ new_cont = init_cont
+ new_init_cont_list.append(json.dumps(init_cont))
+
+ new_payload = ",".join(new_init_cont_list)
+
+ if new_cont:
+ input_dict['spec']['template']['metadata']['annotations'].pop('pod.beta.kubernetes.io/init-containers')
+ input_dict['spec']['template']['metadata']['annotations']['pod.beta.kubernetes.io/init-containers'] = '[{}]'.format(new_payload)
+
+
+ except KeyError as ke:
+ ctx.logger.debug('Readiness section is not found.')
+
+ return input_dict
+
+
+def _get_k8s_b64():
+ target_relationship = _retrieve_managed_by_master()
+
+ k8s_config = target_relationship.node.properties.get('configuration').get('file_content')
+
+ if not k8s_config:
+ raise Exception("Cannot find kubernetes config")
+
+ k8s_config_plain = yaml.dump(k8s_config, allow_unicode=True)
+
+ k8s_config_b64 = base64.b64encode(k8s_config_plain)
+
+ return k8s_config_b64
+
+
+def _get_k8s_b64_env():
+ env = dict()
+ env['name'] = 'K8S_CONFIG_B64'
+ env['value'] = _get_k8s_b64()
+ return env
+
+
+def _retrieve_root_path():
+ target_relationship = _retrieve_depends_on()
+
+ apps_root_path = target_relationship.instance.runtime_properties.get(constants.RT_APPS_ROOT_PATH, None)
+
+ ctx.logger.debug("Retrived apps root path = {}".format(apps_root_path))
+
+ return apps_root_path
+
+def _retrieve_helm_cli_path():
+ target_relationship = _retrieve_depends_on()
+
+ helm_cli_path = target_relationship.instance.runtime_properties.get(constants.RT_HELM_CLI_PATH, None)
+
+ ctx.logger.debug("Retrived helm clis path = {}".format(helm_cli_path))
+
+ return helm_cli_path
+
+def _retrieve_depends_on():
+ result = None
+ for relationship in ctx.instance.relationships:
+ if relationship.type == 'cloudify.relationships.depends_on':
+ return relationship.target
+
+def _retrieve_managed_by_master():
+ result = None
+ for relationship in ctx.instance.relationships:
+ if relationship.type == 'cloudify.kubernetes.relationships.managed_by_master':
+ return relationship.target
diff --git a/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/workarounds.py b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/workarounds.py
new file mode 100644
index 0000000000..fe3e892c5b
--- /dev/null
+++ b/cloudify-onap/plugins/onap-installation-plugin/k8s_installer/common/workarounds.py
@@ -0,0 +1,67 @@
+########
+# Copyright (c) 2017 GigaSpaces Technologies Ltd. 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.
+
+from cloudify import ctx
+from cloudify.exceptions import NonRecoverableError
+
+from fabric import api as fabric_api
+
+def _retrieve_namespace():
+ namespace = ctx.node.properties.get(
+ 'namespace',
+ ctx.node.properties
+ .get('options', {})
+ .get('namespace', None)
+ )
+
+ if not namespace:
+ raise NonRecoverableError(
+ 'Namespace is not defined (node={})'.format(ctx.node.name)
+ )
+
+ return namespace
+
+
+def configure_secret():
+ namespace = _retrieve_namespace()
+ ctx.logger.info(
+ 'Configuring docker secrets for namespace: {0}'.format(namespace)
+ )
+
+ command = 'kubectl create secret ' \
+ 'docker-registry onap-docker-registry-key ' \
+ '--docker-server=nexus3.onap.org:10001 ' \
+ '--docker-username=docker ' \
+ '--docker-password=docker ' \
+ '--docker-email=email@email.com ' \
+ '--namespace={0}'.format(namespace)
+
+ ctx.logger.info('Command "{0}" will be executed'.format(command))
+
+ with fabric_api.settings(
+ **ctx.node.properties.get('ssh_credentials')):
+ fabric_api.run(command)
+
+ ctx.logger.info('Docker secrets configured successfully')
+
+
+def _get_fabric_env():
+ result = dict()
+
+ result['host_string'] = ctx.node.properties.get('ssh_credentials')['host_string']
+ result['user'] = ctx.node.properties.get('ssh_credentials')['user']
+ result['key'] = ctx.node.properties.get('ssh_credentials')['key']
+
+ return result