summaryrefslogtreecommitdiffstats
path: root/helm
diff options
context:
space:
mode:
authorjh245g <jh245g@att.com>2018-06-27 14:50:33 -0400
committerJun (Nicolas) Hu <jh245g@att.com>2018-06-27 19:01:20 +0000
commitd9b88cc5ee987f5fed1011583a172f3c76251814 (patch)
tree36668f1ced1b3de0f13a5d6b8a90c495e032c209 /helm
parentcec8e7c0f90be290796d9a666edeea97e118a26f (diff)
Update helm plugin source code
Change-Id: I1689d8d915c8f18a3e8230dcabb33413a2b9043e Issue-ID: CCSDK-322 Signed-off-by: jh245g <jh245g@att.com>
Diffstat (limited to 'helm')
-rw-r--r--helm/.travis.yml11
-rw-r--r--helm/LICENSE201
-rw-r--r--helm/README.md12
-rw-r--r--helm/circle.yml25
-rw-r--r--helm/dev-requirements.txt6
-rw-r--r--helm/helm-type.yaml129
-rw-r--r--helm/plugin/__init__.py14
-rw-r--r--helm/plugin/tasks.py305
-rw-r--r--helm/plugin/tests/__init__.py14
-rw-r--r--helm/plugin/tests/blueprint/blueprint.yaml42
-rw-r--r--helm/plugin/tests/blueprint/plugin/test_plugin.yaml20
-rw-r--r--helm/plugin/tests/test_plugin.py47
-rw-r--r--helm/plugin/workflows.py64
-rw-r--r--helm/setup.py46
-rw-r--r--helm/tox.ini18
15 files changed, 954 insertions, 0 deletions
diff --git a/helm/.travis.yml b/helm/.travis.yml
new file mode 100644
index 0000000..edb3cf0
--- /dev/null
+++ b/helm/.travis.yml
@@ -0,0 +1,11 @@
+sudo: true
+language: python
+python:
+ - "2.7"
+env:
+ - TOX_ENV=flake8
+ - TOX_ENV=py27
+install:
+ - pip install tox
+script:
+ - tox -e $TOX_ENV
diff --git a/helm/LICENSE b/helm/LICENSE
new file mode 100644
index 0000000..ad410e1
--- /dev/null
+++ b/helm/LICENSE
@@ -0,0 +1,201 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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. \ No newline at end of file
diff --git a/helm/README.md b/helm/README.md
new file mode 100644
index 0000000..4128fba
--- /dev/null
+++ b/helm/README.md
@@ -0,0 +1,12 @@
+cloudify-plugin-template
+========================
+
+[![Build Status](https://travis-ci.org/cloudify-cosmo/cloudify-plugin-template.svg?branch=master)](https://travis-ci.org/cloudify-cosmo/cloudify-plugin-template)
+
+ONAP Helm Plugin.
+This Plugin will utilize the ONAP helm chart to install, uninstall, upgrade, and rollback ONAP components.
+
+## Documents
+
+See https://wiki.onap.org/display/DW/Introduction+of+Helm+Plugin
+
diff --git a/helm/circle.yml b/helm/circle.yml
new file mode 100644
index 0000000..4245150
--- /dev/null
+++ b/helm/circle.yml
@@ -0,0 +1,25 @@
+checkout:
+ post:
+ - >
+ if [ -n "$CI_PULL_REQUEST" ]; then
+ PR_ID=${CI_PULL_REQUEST##*/}
+ git fetch origin +refs/pull/$PR_ID/merge:
+ git checkout -qf FETCH_HEAD
+ fi
+
+dependencies:
+ pre:
+ - pyenv local 2.7.9
+ override:
+ - pip install tox
+
+test:
+ override:
+ - tox -e flake8
+ - tox -e py27
+
+deployment:
+ release:
+ tag: /.*/
+ commands:
+ - (true)
diff --git a/helm/dev-requirements.txt b/helm/dev-requirements.txt
new file mode 100644
index 0000000..48bc5ba
--- /dev/null
+++ b/helm/dev-requirements.txt
@@ -0,0 +1,6 @@
+pyyaml==3.12
+
+-e git+https://github.com/cloudify-cosmo/cloudify-dsl-parser@4.1.1-build#egg=cloudify-dsl-parser==4.1.1
+-e git+https://github.com/cloudify-cosmo/cloudify-rest-client@4.1.1-build#egg=cloudify-rest-client==4.1.1
+-e git+https://github.com/cloudify-cosmo/cloudify-plugins-common@4.1.1-build#egg=cloudify-plugins-common==4.1.1
+nose
diff --git a/helm/helm-type.yaml b/helm/helm-type.yaml
new file mode 100644
index 0000000..2e79849
--- /dev/null
+++ b/helm/helm-type.yaml
@@ -0,0 +1,129 @@
+# ============LICENSE_START==========================================
+# ===================================================================
+# Copyright (c) 2017 AT&T
+#
+# 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============================================
+
+plugins:
+ helm-plugin:
+ executor: central_deployment_agent
+ package_name: onap-helm-plugin
+ package_version: 2.2.0
+
+node_types:
+
+ onap.nodes.component:
+ derived_from: cloudify.nodes.Root
+ properties:
+ tiller-server-ip:
+ description: IP of tiller server
+ type: string
+ tiller-server-port:
+ default: local
+ description: Port of tiller server
+ type: string
+ chart-repo-url:
+ default: local
+ description: helm chart repo url
+ type: string
+ component-name:
+ description: onap component string
+ type: string
+ chart-version:
+ description: helm chart version
+ type: string
+ config-dir:
+ description: config file dir
+ default: '/opt/manager/resources/'
+ type: string
+ namespace:
+ description: k8s namespace
+ default: onap
+ config:
+ description: String format config file
+ type: string
+ default: ''
+ config-url:
+ description: String format config file url
+ type: string
+ default: ''
+ runtime-config:
+ default: ''
+ description: String format json object. To save the runtime config generate from other nodes.
+ tls-enable:
+ description: enable helm TSL
+ type: boolean
+ default: false
+ ca:
+ description: value of ca.pem
+ type: string
+ default: ''
+ cert:
+ description: value of cert.pem
+ type: string
+ default: ''
+ key:
+ description: value of key.pem
+ type: string
+ default: ''
+ stable-repo-url:
+ description: URL for stable repository
+ type: string
+ default: 'https://kubernetes-charts.storage.googleapis.com'
+
+ # This part should handel by Blueprint not plugin
+ # the default docker values points to ONAP nexus3 docker repo.
+ # If need point to other private docker repo you can overrite it in blueprint node templates .
+# docker-server:
+# description: Private Docker Registry FQDN.
+# default: nexus3.onap.org:10001
+# docker-username:
+# description: Docker username.
+# default: docker
+# docker-password:
+# description: Docker password.
+# default: docker
+
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ configure: helm-plugin.plugin.tasks.config
+ start: helm-plugin.plugin.tasks.start
+ stop: helm-plugin.plugin.tasks.stop
+ upgrade: helm-plugin.plugin.tasks.upgrade
+ rollback: helm-plugin.plugin.tasks.rollback
+
+
+workflows:
+ upgrade:
+ mapping: helm-plugin.plugin.workflows.upgrade
+ parameters:
+ node_instance_id:
+ description: The id of the node-instance that you want to modify.
+ config_json:
+ description: The changes to the new config json
+ default: ''
+ config_json_url:
+ description: The changes to the new config json url
+ default: ''
+ chartVersion:
+ description: chart version
+ chartRepo:
+ description: chart repo url
+ rollback:
+ mapping: helm-plugin.plugin.workflows.rollback
+ parameters:
+ node_instance_id:
+ description: The id of the node-instance that you want to modify.
+ revision:
+ description: Check the node runtime property history, find the revision number you want to rollback to
diff --git a/helm/plugin/__init__.py b/helm/plugin/__init__.py
new file mode 100644
index 0000000..749f68f
--- /dev/null
+++ b/helm/plugin/__init__.py
@@ -0,0 +1,14 @@
+########
+# Copyright (c) 2014 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/helm/plugin/tasks.py b/helm/plugin/tasks.py
new file mode 100644
index 0000000..8df29ac
--- /dev/null
+++ b/helm/plugin/tasks.py
@@ -0,0 +1,305 @@
+# ============LICENSE_START==========================================
+# ===================================================================
+# Copyright (c) 2018 AT&T
+#
+# 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 cloudify.decorators import operation
+import shutil
+import errno
+import sys
+import pwd
+import grp
+import os
+import re
+import getpass
+import subprocess
+from cloudify import ctx
+from cloudify.exceptions import OperationRetry
+from cloudify_rest_client.exceptions import CloudifyClientError
+import pip
+import json
+import yaml
+import urllib2
+from cloudify.decorators import operation
+from cloudify import exceptions
+from cloudify.exceptions import NonRecoverableError
+
+
+
+def execute_command(_command):
+ ctx.logger.debug('_command {0}.'.format(_command))
+
+ subprocess_args = {
+ 'args': _command.split(),
+ 'stdout': subprocess.PIPE,
+ 'stderr': subprocess.PIPE
+ }
+
+ ctx.logger.debug('subprocess_args {0}.'.format(subprocess_args))
+
+ process = subprocess.Popen(**subprocess_args)
+ output, error = process.communicate()
+
+ ctx.logger.debug('command: {0} '.format(_command))
+ ctx.logger.debug('output: {0} '.format(output))
+ ctx.logger.debug('error: {0} '.format(error))
+ ctx.logger.debug('process.returncode: {0} '.format(process.returncode))
+
+ if process.returncode:
+ ctx.logger.error('Running `{0}` returns error.'.format(_command))
+ return False
+
+ return output
+
+
+def configure_admin_conf():
+ # Add the kubeadmin config to environment
+ agent_user = getpass.getuser()
+ uid = pwd.getpwnam(agent_user).pw_uid
+ gid = grp.getgrnam('docker').gr_gid
+ admin_file_dest = os.path.join(os.path.expanduser('~'), 'admin.conf')
+
+ execute_command('sudo cp {0} {1}'.format('/etc/kubernetes/admin.conf', admin_file_dest))
+ execute_command('sudo chown {0}:{1} {2}'.format(uid, gid, admin_file_dest))
+
+ with open(os.path.join(os.path.expanduser('~'), '.bashrc'), 'a') as outfile:
+ outfile.write('export KUBECONFIG=$HOME/admin.conf')
+ os.environ['KUBECONFIG'] = admin_file_dest
+
+def get_current_helm_value(chart_name):
+ tiller_host= str(ctx.node.properties['tiller-server-ip'])+':'+str(ctx.node.properties['tiller-server-port'])
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ config_dir=config_dir_root+str(ctx.deployment.id)+'/'
+ if str_to_bool(ctx.node.properties['tls-enable']):
+ getValueCommand=subprocess.Popen(["helm", "get","values","-a",chart_name,'--host',tiller_host,'--tls','--tls-ca-cert',config_dir+'ca.cert.pem','--tls-cert',config_dir+'helm.cert.pem','--tls-key',config_dir+'helm.key.pem'], stdout=subprocess.PIPE)
+ else:
+ getValueCommand=subprocess.Popen(["helm", "get","values","-a",chart_name,'--host',tiller_host], stdout=subprocess.PIPE)
+ value=getValueCommand.communicate()[0]
+ valueMap= {}
+ valueMap = yaml.safe_load(value)
+ ctx.instance.runtime_properties['current-helm-value'] = valueMap
+
+def get_helm_history(chart_name):
+ tiller_host= str(ctx.node.properties['tiller-server-ip'])+':'+str(ctx.node.properties['tiller-server-port'])
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ config_dir=config_dir_root+str(ctx.deployment.id)+'/'
+ if str_to_bool(ctx.node.properties['tls-enable']):
+ getHistoryCommand=subprocess.Popen(["helm", "history",chart_name,'--host',tiller_host,'--tls','--tls-ca-cert',config_dir+'ca.cert.pem','--tls-cert',config_dir+'helm.cert.pem','--tls-key',config_dir+'helm.key.pem'], stdout=subprocess.PIPE)
+ else:
+ getHistoryCommand=subprocess.Popen(["helm", "history",chart_name,'--host',tiller_host], stdout=subprocess.PIPE)
+ history=getHistoryCommand.communicate()[0]
+ history_start_output = [line.strip() for line in history.split('\n') if line.strip()]
+ for index in range(len(history_start_output)):
+ history_start_output[index]=history_start_output[index].replace('\t',' ')
+ ctx.instance.runtime_properties['helm-history'] = history_start_output
+
+def mergedict(dict1, dict2):
+ for key in dict2.keys():
+ if key not in dict1.keys():
+ dict1[key] = dict2[key]
+ else:
+ if type(dict1[key]) == dict and type(dict2[key]) == dict :
+ mergedict(dict1[key], dict2[key])
+ else:
+ dict1[key] = dict2[key]
+
+def tls():
+ if str_to_bool(ctx.node.properties['tls-enable']):
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ config_dir=config_dir_root+str(ctx.deployment.id)+'/'
+ tls_command= ' --tls --tls-ca-cert '+config_dir+'ca.cert.pem --tls-cert '+config_dir+'helm.cert.pem --tls-key '+config_dir+'helm.key.pem '
+ ctx.logger.debug(tls_command)
+ return tls_command
+ else :
+ return ''
+
+def tiller_host():
+ tiller_host= ' --host '+str(ctx.node.properties['tiller-server-ip'])+':'+str(ctx.node.properties['tiller-server-port'])+' '
+ ctx.logger.debug(tiller_host)
+ return tiller_host
+
+
+def str_to_bool(s):
+ s=str(s)
+ if s == 'True' or s == 'true':
+ return True
+ elif s == 'False' or s== 'false':
+ return False
+ else:
+ raise False
+
+
+@operation
+def config(**kwargs):
+ # create helm value file on K8s master
+ #configPath = ctx.node.properties['config-path']
+ configJson = str(ctx.node.properties['config'])
+ configJsonUrl = str(ctx.node.properties['config-url'])
+ runtime_config = str(ctx.node.properties['runtime-config']) #json
+ componentName = ctx.node.properties['component-name']
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ stable_repo_url = str(ctx.node.properties['stable-repo-url'])
+ ctx.logger.debug("debug "+ configJson + runtime_config )
+ #load input config
+ config_dir=config_dir_root+str(ctx.deployment.id)
+ try:
+ os.makedirs(config_dir)
+ except OSError as e:
+ if e.errno != errno.EEXIST:
+ raise
+ ctx.logger.debug('tls-enable type '+str(type(str_to_bool(ctx.node.properties['tls-enable']))) )
+ #create TLS cert files
+ if str_to_bool(ctx.node.properties['tls-enable']):
+ ctx.logger.debug('tls enable' )
+ ca_value = ctx.node.properties['ca']
+ cert_value = ctx.node.properties['cert']
+ key_value = ctx.node.properties['key']
+ ca= open(config_dir+'/ca.cert.pem',"w+")
+ ca.write(ca_value)
+ ca.close()
+ cert= open(config_dir+'/helm.cert.pem',"w+")
+ cert.write(cert_value)
+ cert.close()
+ key= open(config_dir+'/helm.key.pem',"w+")
+ key.write(key_value)
+ key.close()
+ else:
+ ctx.logger.debug('tls disable' )
+
+ # create helm value.yaml file
+ configPath=config_dir_root+str(ctx.deployment.id)+'/'+componentName+'.yaml'
+ ctx.logger.debug(configPath)
+
+ configObj ={}
+ if configJson == '' and configJsonUrl == '':
+ ctx.logger.debug("Will use default HELM value")
+ elif configJson == '' and configJsonUrl != '':
+ response = urllib2.urlopen(configJsonUrl)
+ configObj = json.load(response)
+ elif configJson != '' and configJsonUrl == '':
+ configObj = json.loads(configJson)
+ else:
+ raise NonRecoverableError("Unable to get Json config input")
+
+ # load runtime config
+ ctx.logger.debug("debug check runtime config")
+ if runtime_config == '':
+ ctx.logger.debug("there is no runtime config value")
+ else:
+ runtime_config_obj= json.loads(runtime_config)
+ mergedict(configObj,runtime_config_obj)
+
+ with open(configPath, 'w') as outfile:
+ yaml.safe_dump(configObj, outfile, default_flow_style=False)
+
+ output = execute_command('helm init --client-only --stable-repo-url '+stable_repo_url)
+ if output == False :
+ raise NonRecoverableError("helm init failed")
+
+
+
+
+@operation
+def start(**kwargs):
+ # install the ONAP Helm chart
+ # get properties from node
+ chartRepo = ctx.node.properties['chart-repo-url']
+ componentName = ctx.node.properties['component-name']
+ chartVersion = ctx.node.properties['chart-version']
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ configPath=config_dir_root+str(ctx.deployment.id)+'/'+componentName+'.yaml'
+ namespace = ctx.node.properties['namespace']
+ configJson = str(ctx.node.properties['config'])
+ configJsonUrl = str(ctx.node.properties['config-url'])
+ runtimeconfigJson = str(ctx.node.properties['runtime-config'])
+
+
+ chart = chartRepo + "/" + componentName + "-" + chartVersion + ".tgz"
+ chartName = namespace + "-" + componentName
+
+ if configJson == '' and runtimeconfigJson == '' and configJsonUrl == '':
+ installCommand = 'helm install '+ chart + ' --name ' + chartName + ' --namespace ' + namespace+tiller_host()+tls()
+ else:
+ installCommand = 'helm install ' + chart + ' --name ' + chartName + ' --namespace ' + namespace + ' -f '+ configPath +tiller_host()+tls()
+
+ output =execute_command(installCommand)
+ if output == False :
+ return ctx.operation.retry(message='helm install failed, re-try after 5 second ',
+ retry_after=5)
+
+ get_current_helm_value(chartName)
+ get_helm_history(chartName)
+
+@operation
+def stop(**kwargs):
+ # delete the ONAP helm chart
+ #configure_admin_conf()
+ # get properties from node
+ namespace = ctx.node.properties['namespace']
+ component = ctx.node.properties['component-name']
+ chartName = namespace + "-" + component
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ # Delete helm chart
+ command = 'helm delete --purge '+ chartName+tiller_host()+tls()
+ output =execute_command(command)
+ config_dir=config_dir_root+str(ctx.deployment.id)
+ shutil.rmtree(config_dir)
+ if output == False :
+ raise NonRecoverableError("helm delete failed")
+
+@operation
+def upgrade(**kwargs):
+ # upgrade the helm chart
+ componentName = ctx.node.properties['component-name']
+ config_dir_root= str(ctx.node.properties['config-dir'])
+ configPath=config_dir_root+str(ctx.deployment.id)+'/'+componentName+'.yaml'
+ componentName = ctx.node.properties['component-name']
+ namespace = ctx.node.properties['namespace']
+ configJson = kwargs['config']
+ chartRepo = kwargs['chart_repo']
+ chartVersion = kwargs['chart_version']
+
+ ctx.logger.debug('debug ' + str(configJson))
+ chartName = namespace + "-" + componentName
+ chart=chartRepo + "/" + componentName + "-" + chartVersion + ".tgz"
+ if str(configJson) == '':
+ upgradeCommand = 'helm upgrade '+ chartName + ' '+ chart+tiller_host()+tls()
+ else:
+ with open(configPath, 'w') as outfile:
+ yaml.safe_dump(configJson, outfile, default_flow_style=False)
+ #configure_admin_conf()
+ upgradeCommand = 'helm upgrade '+ chartName + ' '+ chart + ' -f ' + configPath+tiller_host()+tls()
+ output=execute_command(upgradeCommand)
+ if output == False :
+ return ctx.operation.retry(message='helm upgrade failed, re-try after 5 second ',
+ retry_after=5)
+ get_current_helm_value(chartName)
+ get_helm_history(chartName)
+
+@operation
+def rollback(**kwargs):
+ # rollback to some revision
+ componentName = ctx.node.properties['component-name']
+ namespace = ctx.node.properties['namespace']
+ revision = kwargs['revision']
+ #configure_admin_conf()
+ chartName = namespace + "-" + componentName
+ rollbackCommand = 'helm rollback '+ chartName + ' '+ revision+tiller_host()+tls()
+ output=execute_command(rollbackCommand)
+ if output == False :
+ return ctx.operation.retry(message='helm rollback failed, re-try after 5 second ',
+ retry_after=5)
+ get_current_helm_value(chartName)
+ get_helm_history(chartName)
diff --git a/helm/plugin/tests/__init__.py b/helm/plugin/tests/__init__.py
new file mode 100644
index 0000000..749f68f
--- /dev/null
+++ b/helm/plugin/tests/__init__.py
@@ -0,0 +1,14 @@
+########
+# Copyright (c) 2014 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/helm/plugin/tests/blueprint/blueprint.yaml b/helm/plugin/tests/blueprint/blueprint.yaml
new file mode 100644
index 0000000..2588e8d
--- /dev/null
+++ b/helm/plugin/tests/blueprint/blueprint.yaml
@@ -0,0 +1,42 @@
+# DSL version, should appear in the main blueprint.yaml
+# and may appear in other imports. In such case, the versions must match
+tosca_definitions_version: cloudify_dsl_1_3
+
+imports:
+ # importing cloudify related types, plugins, workflow, etc...
+ # to speed things up, it is possible downloading this file,
+ # including it in the blueprint directory and importing it
+ # instead.
+ - http://www.getcloudify.org/spec/cloudify/4.1.1/types.yaml
+ # relative import of plugin.yaml that resides in the blueprint directory
+ - plugin/test_plugin.yaml
+
+inputs:
+ # example input that could be injected by test
+ test_input:
+ description: an input for the test
+ default: default_test_input
+
+node_templates:
+ # defining a single node template that will serve as our test node
+ test_node_template:
+ # using base cloudify type
+ type: cloudify.nodes.Root
+ interfaces:
+ cloudify.interfaces.lifecycle:
+ start:
+ # here we map the single plugin task to the start operation
+ # of the cloudify.interfaces.lifecycle interface
+ implementation: plugin_name.plugin.tasks.my_task
+ inputs:
+ # my_task accepts a single property named
+ # some property. Here we inject this property
+ # from the input provided by the test
+ # (or 'default_test_input' if no input was provided)
+ some_property: { get_input: test_input }
+
+outputs:
+ # example output the could be used to simplify assertions by test
+ test_output:
+ description: an output for the test
+ value: { get_attribute: [test_node_template, some_property] }
diff --git a/helm/plugin/tests/blueprint/plugin/test_plugin.yaml b/helm/plugin/tests/blueprint/plugin/test_plugin.yaml
new file mode 100644
index 0000000..9701318
--- /dev/null
+++ b/helm/plugin/tests/blueprint/plugin/test_plugin.yaml
@@ -0,0 +1,20 @@
+plugins:
+ # Name could be anything, this name is what appears on the beginning of operation
+ # mappings.
+ plugin_name:
+ # Could be 'central_deployment_agent' or 'host_agent'.
+ # If 'central_deployment_agent', this plugin will be executed on the
+ # deployment dedicated agent, other wise it will be executed on the host agent.
+ # We set it the 'central_deployment_agent' here because 'host_agent' plugins should
+ # be contained in a host and this is not required for testing purposes
+ executor: central_deployment_agent
+
+ # Setting install to false in testing environment. In the non-test plugin definition
+ # this property could be omitted usually (its default is true), in which case
+ # the source property should be set
+ install: false
+
+ # source: URL to archive containing the plugin or name of directory containing
+ # the plugin if it is included in the the blueprint directory under the
+ # "plugins" directory. Not required in testing environments as the plugin
+ # need not be installed on any agent
diff --git a/helm/plugin/tests/test_plugin.py b/helm/plugin/tests/test_plugin.py
new file mode 100644
index 0000000..be0882f
--- /dev/null
+++ b/helm/plugin/tests/test_plugin.py
@@ -0,0 +1,47 @@
+########
+# Copyright (c) 2014 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 os import path
+import unittest
+
+from cloudify.test_utils import workflow_test
+
+
+class TestPlugin(unittest.TestCase):
+
+ @workflow_test(path.join('blueprint', 'blueprint.yaml'),
+ resources_to_copy=[(path.join('blueprint', 'plugin',
+ 'test_plugin.yaml'),
+ 'plugin')],
+ inputs={'test_input': 'new_test_input'})
+ def test_my_task(self, cfy_local):
+ # execute install workflow
+ """
+
+ :param cfy_local:
+ """
+ cfy_local.execute('install', task_retries=0)
+
+ # extract single node instance
+ instance = cfy_local.storage.get_node_instances()[0]
+
+ # assert runtime properties is properly set in node instance
+ self.assertEqual(instance.runtime_properties['some_property'],
+ 'new_test_input')
+
+ # assert deployment outputs are ok
+ self.assertDictEqual(cfy_local.outputs(),
+ {'test_output': 'new_test_input'})
diff --git a/helm/plugin/workflows.py b/helm/plugin/workflows.py
new file mode 100644
index 0000000..d341bf7
--- /dev/null
+++ b/helm/plugin/workflows.py
@@ -0,0 +1,64 @@
+# ============LICENSE_START==========================================
+# ===================================================================
+# Copyright (c) 2018 AT&T
+#
+# 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 cloudify.decorators import workflow
+from cloudify.workflows import ctx
+from cloudify.exceptions import NonRecoverableError
+import urllib2
+import json
+
+@workflow
+def upgrade(node_instance_id,config_json,config_json_url,chartVersion,chartRepo,**kwargs):
+ node_instance = ctx.get_node_instance(node_instance_id)
+
+ if not node_instance_id:
+ raise NonRecoverableError(
+ 'No such node_instance_id in deployment: {0}.'.format(
+ node_instance_id))
+
+ kwargs = {}
+ if config_json == '' and config_json_url == '':
+ kwargs['config'] = config_json
+ elif config_json == '' and config_json_url != '':
+ response = urllib2.urlopen(config_json_url)
+ kwargs['config'] = json.load(response)
+ elif config_json != '' and config_json_url == '':
+ kwargs['config'] = config_json
+ else:
+ raise NonRecoverableError("Unable to get Json config input")
+
+ kwargs['chart_version'] = str(chartVersion)
+ kwargs['chart_repo'] = str(chartRepo)
+ operation_args = {'operation': 'upgrade',}
+ operation_args['kwargs'] = kwargs
+ node_instance.execute_operation(**operation_args)
+
+
+@workflow
+def rollback(node_instance_id,revision,**kwargs):
+ node_instance = ctx.get_node_instance(node_instance_id)
+
+ if not node_instance_id:
+ raise NonRecoverableError(
+ 'No such node_instance_id in deployment: {0}.'.format(
+ node_instance_id))
+
+ kwargs = {}
+ kwargs['revision'] = str(revision)
+ operation_args = {'operation': 'rollback',}
+ operation_args['kwargs'] = kwargs
+ node_instance.execute_operation(**operation_args)
diff --git a/helm/setup.py b/helm/setup.py
new file mode 100644
index 0000000..c3bfe88
--- /dev/null
+++ b/helm/setup.py
@@ -0,0 +1,46 @@
+# ============LICENSE_START==========================================
+# ===================================================================
+# Copyright (c) 2018 AT&T
+#
+# 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 setuptools import setup
+
+# Replace the place holders with values for your project
+
+setup(
+
+ # Do not use underscores in the plugin name.
+ name='onap-helm-plugin',
+ version='2.2.0',
+ author='Nicolas Hu(AT&T)',
+ author_email='jh245g@att.com',
+ description='This plugin will install/uninstall/upgrade/rollback helm charts of ONAP components. ',
+
+ # This must correspond to the actual packages in the plugin.
+ packages=['plugin'],
+
+ license='LICENSE',
+ zip_safe=False,
+ install_requires=[
+ # Necessary dependency for developing plugins, do not remove!
+ 'pyyaml>=3.12',
+ "cloudify-plugins-common>=4.1.1"
+ ],
+ test_requires=[
+ "cloudify-dsl-parser>=4.1.1"
+ "nose"
+ ]
+)
diff --git a/helm/tox.ini b/helm/tox.ini
new file mode 100644
index 0000000..14c340c
--- /dev/null
+++ b/helm/tox.ini
@@ -0,0 +1,18 @@
+# content of: tox.ini , put in same dir as setup.py
+[tox]
+envlist=flake8,py27
+
+[testenv:py27]
+deps =
+ # this fixes issue with tox installing coverage --pre
+ coverage==3.7.1
+ nose-cov
+ testfixtures
+ -rdev-requirements.txt
+commands=nosetests --with-cov --cov-report term-missing --cov plugin plugin/tests
+
+[testenv:flake8]
+deps =
+ flake8
+ -rdev-requirements.txt
+commands=flake8 plugin