1
16
17 package releaseutil
18
19 import (
20 "log"
21 "path"
22 "sort"
23 "strconv"
24 "strings"
25
26 "github.com/pkg/errors"
27 "sigs.k8s.io/yaml"
28
29 "helm.sh/helm/v3/pkg/chartutil"
30 "helm.sh/helm/v3/pkg/release"
31 )
32
33
34 type Manifest struct {
35 Name string
36 Content string
37 Head *SimpleHead
38 }
39
40
41 type manifestFile struct {
42 entries map[string]string
43 path string
44 apis chartutil.VersionSet
45 }
46
47
48 type result struct {
49 hooks []*release.Hook
50 generic []Manifest
51 }
52
53
54
55 var events = map[string]release.HookEvent{
56 release.HookPreInstall.String(): release.HookPreInstall,
57 release.HookPostInstall.String(): release.HookPostInstall,
58 release.HookPreDelete.String(): release.HookPreDelete,
59 release.HookPostDelete.String(): release.HookPostDelete,
60 release.HookPreUpgrade.String(): release.HookPreUpgrade,
61 release.HookPostUpgrade.String(): release.HookPostUpgrade,
62 release.HookPreRollback.String(): release.HookPreRollback,
63 release.HookPostRollback.String(): release.HookPostRollback,
64 release.HookTest.String(): release.HookTest,
65
66 "test-success": release.HookTest,
67 }
68
69
70
71
72
73
74
75
76
77
78 func SortManifests(files map[string]string, apis chartutil.VersionSet, ordering KindSortOrder) ([]*release.Hook, []Manifest, error) {
79 result := &result{}
80
81 var sortedFilePaths []string
82 for filePath := range files {
83 sortedFilePaths = append(sortedFilePaths, filePath)
84 }
85 sort.Strings(sortedFilePaths)
86
87 for _, filePath := range sortedFilePaths {
88 content := files[filePath]
89
90
91
92 if strings.HasPrefix(path.Base(filePath), "_") {
93 continue
94 }
95
96 if strings.TrimSpace(content) == "" {
97 continue
98 }
99
100 manifestFile := &manifestFile{
101 entries: SplitManifests(content),
102 path: filePath,
103 apis: apis,
104 }
105
106 if err := manifestFile.sort(result); err != nil {
107 return result.hooks, result.generic, err
108 }
109 }
110
111 return sortHooksByKind(result.hooks, ordering), sortManifestsByKind(result.generic, ordering), nil
112 }
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 func (file *manifestFile) sort(result *result) error {
134
135 var sortedEntryKeys []string
136 for entryKey := range file.entries {
137 sortedEntryKeys = append(sortedEntryKeys, entryKey)
138 }
139 sort.Sort(BySplitManifestsOrder(sortedEntryKeys))
140
141 for _, entryKey := range sortedEntryKeys {
142 m := file.entries[entryKey]
143
144 var entry SimpleHead
145 if err := yaml.Unmarshal([]byte(m), &entry); err != nil {
146 return errors.Wrapf(err, "YAML parse error on %s", file.path)
147 }
148
149 if !hasAnyAnnotation(entry) {
150 result.generic = append(result.generic, Manifest{
151 Name: file.path,
152 Content: m,
153 Head: &entry,
154 })
155 continue
156 }
157
158 hookTypes, ok := entry.Metadata.Annotations[release.HookAnnotation]
159 if !ok {
160 result.generic = append(result.generic, Manifest{
161 Name: file.path,
162 Content: m,
163 Head: &entry,
164 })
165 continue
166 }
167
168 hw := calculateHookWeight(entry)
169
170 h := &release.Hook{
171 Name: entry.Metadata.Name,
172 Kind: entry.Kind,
173 Path: file.path,
174 Manifest: m,
175 Events: []release.HookEvent{},
176 Weight: hw,
177 DeletePolicies: []release.HookDeletePolicy{},
178 }
179
180 isUnknownHook := false
181 for _, hookType := range strings.Split(hookTypes, ",") {
182 hookType = strings.ToLower(strings.TrimSpace(hookType))
183 e, ok := events[hookType]
184 if !ok {
185 isUnknownHook = true
186 break
187 }
188 h.Events = append(h.Events, e)
189 }
190
191 if isUnknownHook {
192 log.Printf("info: skipping unknown hook: %q", hookTypes)
193 continue
194 }
195
196 result.hooks = append(result.hooks, h)
197
198 operateAnnotationValues(entry, release.HookDeleteAnnotation, func(value string) {
199 h.DeletePolicies = append(h.DeletePolicies, release.HookDeletePolicy(value))
200 })
201 }
202
203 return nil
204 }
205
206
207 func hasAnyAnnotation(entry SimpleHead) bool {
208 return entry.Metadata != nil &&
209 entry.Metadata.Annotations != nil &&
210 len(entry.Metadata.Annotations) != 0
211 }
212
213
214
215
216 func calculateHookWeight(entry SimpleHead) int {
217 hws := entry.Metadata.Annotations[release.HookWeightAnnotation]
218 hw, err := strconv.Atoi(hws)
219 if err != nil {
220 hw = 0
221 }
222 return hw
223 }
224
225
226 func operateAnnotationValues(entry SimpleHead, annotation string, operate func(p string)) {
227 if dps, ok := entry.Metadata.Annotations[annotation]; ok {
228 for _, dp := range strings.Split(dps, ",") {
229 dp = strings.ToLower(strings.TrimSpace(dp))
230 operate(dp)
231 }
232 }
233 }
234
View as plain text