2 # Copyright (c) 2017 GigaSpaces Technologies Ltd. All rights reserved
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # * See the License for the specific language governing permissions and
14 # * limitations under the License.
18 import cloudify_kubernetes.tasks as kubernetes_plugin
20 from cloudify import ctx
21 from cloudify.exceptions import NonRecoverableError
24 import deployment_result
30 SERVICES_FILE_PARTS_SEPARATOR = '---'
33 def create_resoruces():
34 ctx.logger.info('Creating resources')
35 apps_path = _retrieve_root_path()
39 'Apps dir is not defined. Skipping!'
44 helm_app = ctx.node.properties.get('path', None)
46 yaml_file = prepare_content(helm_app)
48 yaml_content_parts = yaml_file.split(SERVICES_FILE_PARTS_SEPARATOR)
50 for yaml_content_part in yaml_content_parts:
52 yaml_content = _apply_readiness_workaround(yaml_content_part)
54 create_resource(yaml_content)
56 ctx.logger.info('Resource created successfully')
58 def delete_resoruces():
60 ctx.logger.info('Deleting resources')
61 apps_path = _retrieve_root_path()
65 'Apps dir is not defined. Skipping!'
69 helm_app = ctx.node.properties.get('path', None)
71 yaml_file = prepare_content(helm_app)
73 yaml_content_parts = yaml_file.split(SERVICES_FILE_PARTS_SEPARATOR)
75 for yaml_content_part in yaml_content_parts:
77 yaml_content = _apply_readiness_workaround(yaml_content_part)
79 delete_resource(yaml_content)
81 ctx.logger.info('Resources deleted successfully')
84 def prepare_content(resource):
85 helm_path = _retrieve_helm_cli_path()
86 yaml_file = render_chart(resource, _retrieve_root_path(), helm_path)
91 def create_resource(yaml_content_dict):
92 ctx.logger.debug("Loading yaml: {}".format(yaml_content_dict))
94 if yaml_content_dict.get('kind', '') == 'PersistentVolumeClaim':
95 ctx.logger.debug("PersistentVolumeClaim custom handling")
96 kubernetes_plugin.custom_resource_create(definition=yaml_content_dict, api_mapping=_get_persistent_volume_mapping_claim_api())
98 kubernetes_plugin.resource_create(definition=yaml_content_dict)
100 deployment_result.save_deployment_result('resource_{0}'.format(yaml_content_dict['metadata']['name']))
102 def delete_resource(yaml_content_dict):
103 ctx.logger.debug("Loading yaml: {}".format(yaml_content_dict))
105 deployment_result.save_deployment_result('resource_{0}'.format(yaml_content_dict['metadata']['name']))
106 if yaml_content_dict.get('kind', '') == 'PersistentVolumeClaim':
107 ctx.logger.debug("PersistentVolumeClaim custom handling")
108 kubernetes_plugin.custom_resource_delete(definition=yaml_content_dict, api_mapping=_get_persistent_volume_mapping_claim_api())
110 kubernetes_plugin.resource_delete(definition=yaml_content_dict)
113 def render_chart(app, app_root_path, helm_cli_path):
114 app_chart_path = "{}/{}/".format(app_root_path, app)
115 ctx.logger.debug('App chart path = {}'.format(app_chart_path))
116 return _exec_helm_template(helm_cli_path, app_chart_path)
119 def _exec_helm_template(helm_path, chart):
120 cmd = '{0} template {1}'.format(helm_path, chart)
121 ctx.logger.debug('Executing helm template cmd: {}'.format(cmd))
122 rendered = subprocess.Popen(cmd.split(" "), stdout=subprocess.PIPE).stdout.read().decode()
126 def _get_persistent_volume_mapping_claim_api():
130 'method': 'create_namespaced_persistent_volume_claim',
131 'payload': 'V1PersistentVolumeClaim'
135 'method': 'read_namespaced_persistent_volume_claim',
139 'method': 'delete_namespaced_persistent_volume_claim',
140 'payload': 'V1DeleteOptions'
147 def _apply_readiness_workaround(yaml_file):
148 b64_env = _get_k8s_b64_env()
150 input_dict = yaml.load(yaml_file)
153 init_containers = input_dict['spec']['template']['metadata']['annotations'][
154 'pod.beta.kubernetes.io/init-containers']
155 init_cont_list = eval(init_containers)
157 new_init_cont_list = list()
159 for init_cont in init_cont_list:
160 if "oomk8s/readiness-check" in init_cont['image']:
161 init_cont['image'] = "clfy/oomk8s-cfy-readiness-check:1.0.1"
162 #init_cont['imagePullPolicy'] = "IfNotPresent"
163 init_cont['env'].append(b64_env)
165 new_init_cont_list.append(json.dumps(init_cont))
167 new_payload = ",".join(new_init_cont_list)
170 input_dict['spec']['template']['metadata']['annotations'].pop('pod.beta.kubernetes.io/init-containers')
171 input_dict['spec']['template']['metadata']['annotations']['pod.beta.kubernetes.io/init-containers'] = '[{}]'.format(new_payload)
174 except KeyError as ke:
175 ctx.logger.debug('Readiness section is not found.')
181 target_relationship = _retrieve_managed_by_master()
183 k8s_config = target_relationship.node.properties.get('configuration').get('file_content')
186 raise Exception("Cannot find kubernetes config")
188 k8s_config_plain = yaml.dump(k8s_config, allow_unicode=True)
190 k8s_config_b64 = base64.b64encode(k8s_config_plain)
192 return k8s_config_b64
195 def _get_k8s_b64_env():
197 env['name'] = 'K8S_CONFIG_B64'
198 env['value'] = _get_k8s_b64()
202 def _retrieve_root_path():
203 target_relationship = _retrieve_depends_on()
205 apps_root_path = target_relationship.instance.runtime_properties.get(constants.RT_APPS_ROOT_PATH, None)
207 ctx.logger.debug("Retrived apps root path = {}".format(apps_root_path))
209 return apps_root_path
211 def _retrieve_helm_cli_path():
212 target_relationship = _retrieve_depends_on()
214 helm_cli_path = target_relationship.instance.runtime_properties.get(constants.RT_HELM_CLI_PATH, None)
216 ctx.logger.debug("Retrived helm clis path = {}".format(helm_cli_path))
220 def _retrieve_depends_on():
222 for relationship in ctx.instance.relationships:
223 if relationship.type == 'cloudify.relationships.depends_on':
224 return relationship.target
226 def _retrieve_managed_by_master():
228 for relationship in ctx.instance.relationships:
229 if relationship.type == 'cloudify.kubernetes.relationships.managed_by_master':
230 return relationship.target