blob: 7a66b100762533a50ec1a60156c656bfaa2231e6 [file] [log] [blame]
Yuriy Taradayaeeaa742017-06-28 15:54:56 +04001import difflib
tmeneaud92f4742017-10-18 09:57:19 -04002import os
3import logging
Yuriy Taraday84a21032017-06-27 11:13:16 +04004
tmeneaud92f4742017-10-18 09:57:19 -04005from salt.exceptions import CommandExecutionError
Yuriy Taradayaeeaa742017-06-28 15:54:56 +04006from salt.serializers import yaml
7
tmeneaud92f4742017-10-18 09:57:19 -04008LOG = logging.getLogger(__name__)
Yuriy Taraday76126042017-08-11 15:27:41 +04009
tmeneaud92f4742017-10-18 09:57:19 -040010def _get_values_from_file(values_file=None):
11 if values_file:
12 try:
13 with open(values_file) as values_stream:
14 values = yaml.deserialize(values_stream)
15 return values
16 except e:
17 raise CommandExecutionError("encountered error reading from values "
18 "file (%s): %s" % (values_file, e))
19 return None
20
21def _get_yaml_diff(new_yaml=None, old_yaml=None):
22 if not new_yaml and not old_yaml:
23 return None
24
25 old_str = yaml.serialize(old_yaml, default_flow_style=False)
26 new_str = yaml.serialize(new_yaml, default_flow_style=False)
27 return difflib.unified_diff(old_str.split('\n'), new_str.split('\n'))
28
29def _failure(name, message, changes={}):
Yuriy Taraday76126042017-08-11 15:27:41 +040030 return {
31 'name': name,
tmeneaud92f4742017-10-18 09:57:19 -040032 'changes': changes,
Yuriy Taraday76126042017-08-11 15:27:41 +040033 'result': False,
34 'comment': message,
35 }
36
tmeneau94bf68e2017-10-17 15:55:34 -040037def present(name, chart_name, namespace, version=None, values_file=None,
tmeneaud92f4742017-10-18 09:57:19 -040038 tiller_namespace='kube-system', **kwargs):
39 '''
40 Ensure that a release with the supplied name is in the desired state in the
41 Tiller installation. This state will handle change detection to determine
42 whether an installation or update needs to be made.
43
44 In the event the namespace to which a release is installed changes, the
45 state will first delete and purge the release and the re-install it into
46 the new namespace, since Helm does not support updating a release into a
47 new namespace.
48
49 name
50 The name of the release to ensure is present
51
52 chart_name
53 The name of the chart to install, including the repository name as
54 applicable (such as `stable/mysql`)
55
56 namespace
57 The namespace to which the release should be (re-)installed
58
59 version
60 The version of the chart to install. Defaults to the latest version
61
62 values_file
63 The path to the a values file containing all the chart values that
64 should be applied to the release. Note that this should not be passed
65 if there are not chart value overrides required.
66
67 '''
68 kwargs['tiller_namespace'] = tiller_namespace
69 old_release = __salt__['helm.get_release'](name, **kwargs)
70 if not old_release:
Yuriy Taraday6618fb92017-08-11 17:11:48 +040071 err = __salt__['helm.release_create'](
tmeneaud92f4742017-10-18 09:57:19 -040072 name, chart_name, namespace, version, values_file, **kwargs
73 )
Yuriy Taraday6618fb92017-08-11 17:11:48 +040074 if err:
tmeneaud92f4742017-10-18 09:57:19 -040075 return _failure(name, err)
Yuriy Taraday76126042017-08-11 15:27:41 +040076 return {
77 'name': name,
tmeneaud92f4742017-10-18 09:57:19 -040078 'changes': {
79 'name': name,
80 'chart_name': chart_name,
81 'namespace': namespace,
82 'version': version,
83 'values': _get_values_from_file(values_file)
84 },
Yuriy Taraday76126042017-08-11 15:27:41 +040085 'result': True,
86 'comment': 'Release "{}" was created'.format(name),
87 }
88
tmeneaud92f4742017-10-18 09:57:19 -040089 changes = {}
90 warnings = []
91 if old_release.get('chart') != chart_name.split("/")[1]:
92 changes['chart'] = { 'old': old_release['chart'], 'new': chart_name }
Yuriy Taraday76126042017-08-11 15:27:41 +040093
tmeneaud92f4742017-10-18 09:57:19 -040094 if old_release.get('version') != version:
95 changes['version'] = { 'old': old_release['version'], 'new': version }
Yuriy Taraday76126042017-08-11 15:27:41 +040096
tmeneaud92f4742017-10-18 09:57:19 -040097 if old_release.get('namespace') != namespace:
98 changes['namespace'] = { 'old': old_release['namespace'], 'new': namespace }
99
100 if (not values_file and old_release.get("values") or
101 not old_release.get("values") and values_file):
102 changes['values'] = { 'old': old_release['values'], 'new': values_file }
103
104 values = _get_values_from_file(values_file)
105 diff = _get_yaml_diff(values, old_release.get('values'))
106
107 if diff:
108 diff_string = '\n'.join(diff)
109 if diff_string:
110 changes['values'] = diff_string
111
112 if not changes:
113 return {
Yuriy Taraday84a21032017-06-27 11:13:16 +0400114 'name': name,
tmeneaud92f4742017-10-18 09:57:19 -0400115 'result': True,
116 'changes': {},
117 'comment': 'Release "{}" is already in the desired state'.format(name)
118 }
119
120 module_fn = 'helm.release_upgrade'
121 if changes.get("namespace"):
122 LOG.debug("purging old release (%s) due to namespace change" % name)
123 err = __salt__['helm.release_delete'](name, **kwargs)
124 if err:
125 return _failure(name, err, changes)
126 module_fn = 'helm.release_create'
127 warnings.append('Release (%s) was replaced due to namespace change' % name)
128
129 err = __salt__[module_fn](
130 name, chart_name, namespace, version, values_file, **kwargs
131 )
132 if err:
133 return _failure(name, err, changes)
134
135 ret = {
136 'name': name,
137 'changes': changes,
Yuriy Taraday84a21032017-06-27 11:13:16 +0400138 'result': True,
Yuriy Taraday3c3f63c2017-06-29 20:46:20 +0400139 'comment': 'Release "{}" was updated'.format(name),
Yuriy Taraday84a21032017-06-27 11:13:16 +0400140 }
Yuriy Taraday893b3fb2017-07-03 16:22:57 +0400141
tmeneaud92f4742017-10-18 09:57:19 -0400142 if warnings:
143 ret['warnings'] = warnings
Yuriy Taraday893b3fb2017-07-03 16:22:57 +0400144
tmeneaud92f4742017-10-18 09:57:19 -0400145 return ret
146
147
148def absent(name, tiller_namespace='kube-system', **kwargs):
149 '''
150 Ensure that any release with the supplied release name is absent from the
151 tiller installation.
152
153 name
154 The name of the release to ensure is absent
155 '''
156 kwargs['tiller_namespace'] = tiller_namespace
157 exists = __salt__['helm.release_exists'](name, **kwargs)
Yuriy Taraday893b3fb2017-07-03 16:22:57 +0400158 if not exists:
159 return {
160 'name': name,
161 'changes': {},
162 'result': True,
163 'comment': 'Release "{}" doesn\'t exist'.format(name),
164 }
tmeneau8cf4fce2017-10-17 15:05:35 -0400165 err = __salt__['helm.release_delete'](name, **kwargs)
Yuriy Taraday6618fb92017-08-11 17:11:48 +0400166 if err:
tmeneaud92f4742017-10-18 09:57:19 -0400167 return _failure(name, err)
Yuriy Taraday893b3fb2017-07-03 16:22:57 +0400168 return {
169 'name': name,
170 'changes': {name: 'DELETED'},
171 'result': True,
172 'comment': 'Release "{}" was deleted'.format(name),
173 }