kubelatte-ce

Форк
2
Форк от sbertech/kubelatte-ce
/
pods_mutation.go 
244 строки · 5.9 Кб
1
package mutation
2

3
import (
4
	"github.com/jmespath/go-jmespath"
5
	"sigs.k8s.io/yaml"
6
	"strings"
7
)
8

9
type UpdateStrategy string
10

11
const (
12
	ReplaceStrategy UpdateStrategy = "replace"
13
	MergeStrategy   UpdateStrategy = "merge"
14
)
15

16
type detailedRefTemplateObjectsData struct {
17
	containers  map[string][]string
18
	annotations map[string][]string
19
	volumes     map[string][]string
20
}
21

22
func prepareDataForUniversalMutation(containers []string, annotations []string, volumes []string) (attitude detailedRefTemplateObjectsData) {
23
	attitude = detailedRefTemplateObjectsData{
24
		containers:  make(map[string][]string),
25
		annotations: make(map[string][]string),
26
		volumes:     make(map[string][]string),
27
	}
28

29
	attitude.containers = appendCutElem(attitude.containers, containers)
30
	attitude.annotations = appendCutElem(attitude.annotations, annotations)
31
	attitude.volumes = appendCutElem(attitude.volumes, volumes)
32

33
	return attitude
34
}
35

36
func appendCutElem(attitude map[string][]string, elems []string) map[string][]string {
37
	for _, elem := range elems {
38
		ref := strings.Split(elem, "/")
39
		cutInfo := ref[0] + "/" + ref[1]
40

41
		attitude[cutInfo] = append(attitude[cutInfo], strings.Join(ref[2:], "/"))
42
	}
43

44
	return attitude
45
}
46

47
func getPatchForContainer(specData interface{}, contName string, obj map[string]interface{}, strategy UpdateStrategy) []string {
48
	spec, ok := specData.(map[string]interface{})["spec"]
49
	if !ok {
50
		return nil
51
	}
52
	containers, ok := spec.(map[string]interface{})["containers"]
53
	if !ok {
54
		return nil
55
	}
56

57
	var patches []string
58

59
	for _, contToInsert := range containers.([]interface{}) {
60
		res, ok := contToInsert.(map[string]interface{})["name"]
61
		if !ok || res != contName {
62
			continue
63
		}
64

65
		if strategy == MergeStrategy {
66
			patches = append(patches, getPatchForContainerMergeStrategy(contToInsert.(map[string]interface{})))
67
		}
68

69
		if strategy == ReplaceStrategy {
70
			patches = append(patches, getPatchForContainerReplaceStrategy(contName, obj, contToInsert.(map[string]interface{})))
71
		}
72
	}
73

74
	return patches
75
}
76

77
func getPatchForContainerMergeStrategy(contToInsert map[string]interface{}) string {
78
	withFantic := map[string]map[string][]map[string]interface{}{"spec": {"containers": {contToInsert}}}
79
	yamlPatch, err := yaml.Marshal(withFantic)
80
	if err != nil {
81
		return ""
82
	}
83
	return string(yamlPatch)
84
}
85

86
func getPatchForContainerReplaceStrategy(contName string, obj, contToInsert map[string]interface{}) string {
87
	objConts, err := jmespath.Search("spec.containers", obj)
88
	if err != nil || objConts == nil {
89
		return ""
90
	}
91

92
	objContainers, ok := objConts.([]interface{})
93
	if !ok {
94
		return ""
95
	}
96

97
	var yamlPatch []byte
98

99
	for i := range objContainers {
100
		item := objContainers[i].(map[string]interface{})
101
		if item["name"] != contName {
102
			continue
103
		}
104

105
		objContainers[i] = contToInsert
106
		withFantic := map[string]map[string][]interface{}{"spec": {"containers": objContainers}}
107
		yamlPatch, err = yaml.Marshal(withFantic)
108
		if err != nil {
109
			return ""
110
		}
111
	}
112

113
	if len(yamlPatch) != 0 {
114
		return string(yamlPatch)
115
	}
116

117
	objContainers = append(objContainers, contToInsert)
118

119
	withFantic := map[string]map[string][]interface{}{"spec": {"containers": objContainers}}
120
	yamlPatch, err = yaml.Marshal(withFantic)
121
	if err != nil {
122
		return ""
123
	}
124

125
	return string(yamlPatch)
126
}
127

128
func getPatchForVolume(specData interface{}, volName string, obj map[string]interface{}, strategy UpdateStrategy) []string {
129
	spec, ok := specData.(map[string]interface{})["spec"]
130
	if !ok {
131
		return nil
132
	}
133
	volumes, ok := spec.(map[string]interface{})["volumes"]
134
	if !ok {
135
		return nil
136
	}
137

138
	var patches []string
139

140
	for _, volToInsert := range volumes.([]interface{}) {
141
		res, ok := volToInsert.(map[string]interface{})["name"]
142
		if !ok || res != volName {
143
			continue
144
		}
145

146
		if strategy == MergeStrategy {
147
			patches = append(patches, getPatchForVolumeMergeStrategy(volToInsert.(map[string]interface{})))
148
		}
149
		if strategy == ReplaceStrategy {
150
			patches = append(patches, getPatchForVolumeReplaceStrategy(volName, obj, volToInsert.(map[string]interface{})))
151
		}
152
	}
153

154
	return patches
155
}
156

157
func getPatchForVolumeMergeStrategy(volToInsert map[string]interface{}) string {
158
	withFantic := map[string]map[string][]map[string]interface{}{"spec": {"volumes": {volToInsert}}}
159
	yamlPatch, err := yaml.Marshal(withFantic)
160
	if err != nil {
161
		return ""
162
	}
163
	return string(yamlPatch)
164
}
165

166
func getPatchForVolumeReplaceStrategy(volName string, obj, volToInsert map[string]interface{}) string {
167
	objVols, err := jmespath.Search("spec.volumes", obj)
168
	if err != nil || objVols == nil {
169
		return ""
170
	}
171

172
	objVolumes, ok := objVols.([]interface{})
173
	if !ok {
174
		return ""
175
	}
176

177
	var yamlPatch []byte
178

179
	for i := range objVolumes {
180
		if objVolumes[i].(map[string]interface{})["name"] != volName {
181
			continue
182
		}
183
		objVolumes[i] = volToInsert
184
		withFantic := map[string]map[string][]interface{}{"spec": {"volumes": objVolumes}}
185
		yamlPatch, err = yaml.Marshal(withFantic)
186
		if err != nil {
187
			return ""
188
		}
189

190
	}
191

192
	if len(yamlPatch) != 0 {
193
		return string(yamlPatch)
194
	}
195

196
	objVolumes = append(objVolumes, volToInsert)
197

198
	withFantic := map[string]map[string][]interface{}{"spec": {"volumes": objVolumes}}
199
	yamlPatch, err = yaml.Marshal(withFantic)
200
	if err != nil {
201
		return ""
202
	}
203
	return string(yamlPatch)
204
}
205

206
func getPatchForAnnotation(specData interface{}, annName string) []string {
207
	metadata, ok := specData.(map[string]interface{})["metadata"]
208
	if !ok {
209
		return nil
210
	}
211
	annots, ok := metadata.(map[string]interface{})["annotations"]
212
	if !ok {
213
		return nil
214
	}
215

216
	val, ok := annots.(map[string]interface{})[annName]
217
	if !ok {
218
		return nil
219
	}
220

221
	withFantic := map[string]map[string]map[string]interface{}{"metadata": {"annotations": {annName: val}}}
222
	yamlPatch, err := yaml.Marshal(withFantic)
223
	if err != nil {
224
		return nil
225
	}
226

227
	return []string{string(yamlPatch)}
228
}
229

230
func convert(i interface{}) interface{} {
231
	switch x := i.(type) {
232
	case map[interface{}]interface{}:
233
		m2 := map[string]interface{}{}
234
		for k, v := range x {
235
			m2[k.(string)] = convert(v)
236
		}
237
		return m2
238
	case []interface{}:
239
		for i, v := range x {
240
			x[i] = convert(v)
241
		}
242
	}
243
	return i
244
}
245

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.