kubelatte-ce
Форк от sbertech/kubelatte-ce
244 строки · 5.9 Кб
1package mutation2
3import (4"github.com/jmespath/go-jmespath"5"sigs.k8s.io/yaml"6"strings"7)
8
9type UpdateStrategy string10
11const (12ReplaceStrategy UpdateStrategy = "replace"13MergeStrategy UpdateStrategy = "merge"14)
15
16type detailedRefTemplateObjectsData struct {17containers map[string][]string18annotations map[string][]string19volumes map[string][]string20}
21
22func prepareDataForUniversalMutation(containers []string, annotations []string, volumes []string) (attitude detailedRefTemplateObjectsData) {23attitude = detailedRefTemplateObjectsData{24containers: make(map[string][]string),25annotations: make(map[string][]string),26volumes: make(map[string][]string),27}28
29attitude.containers = appendCutElem(attitude.containers, containers)30attitude.annotations = appendCutElem(attitude.annotations, annotations)31attitude.volumes = appendCutElem(attitude.volumes, volumes)32
33return attitude34}
35
36func appendCutElem(attitude map[string][]string, elems []string) map[string][]string {37for _, elem := range elems {38ref := strings.Split(elem, "/")39cutInfo := ref[0] + "/" + ref[1]40
41attitude[cutInfo] = append(attitude[cutInfo], strings.Join(ref[2:], "/"))42}43
44return attitude45}
46
47func getPatchForContainer(specData interface{}, contName string, obj map[string]interface{}, strategy UpdateStrategy) []string {48spec, ok := specData.(map[string]interface{})["spec"]49if !ok {50return nil51}52containers, ok := spec.(map[string]interface{})["containers"]53if !ok {54return nil55}56
57var patches []string58
59for _, contToInsert := range containers.([]interface{}) {60res, ok := contToInsert.(map[string]interface{})["name"]61if !ok || res != contName {62continue63}64
65if strategy == MergeStrategy {66patches = append(patches, getPatchForContainerMergeStrategy(contToInsert.(map[string]interface{})))67}68
69if strategy == ReplaceStrategy {70patches = append(patches, getPatchForContainerReplaceStrategy(contName, obj, contToInsert.(map[string]interface{})))71}72}73
74return patches75}
76
77func getPatchForContainerMergeStrategy(contToInsert map[string]interface{}) string {78withFantic := map[string]map[string][]map[string]interface{}{"spec": {"containers": {contToInsert}}}79yamlPatch, err := yaml.Marshal(withFantic)80if err != nil {81return ""82}83return string(yamlPatch)84}
85
86func getPatchForContainerReplaceStrategy(contName string, obj, contToInsert map[string]interface{}) string {87objConts, err := jmespath.Search("spec.containers", obj)88if err != nil || objConts == nil {89return ""90}91
92objContainers, ok := objConts.([]interface{})93if !ok {94return ""95}96
97var yamlPatch []byte98
99for i := range objContainers {100item := objContainers[i].(map[string]interface{})101if item["name"] != contName {102continue103}104
105objContainers[i] = contToInsert106withFantic := map[string]map[string][]interface{}{"spec": {"containers": objContainers}}107yamlPatch, err = yaml.Marshal(withFantic)108if err != nil {109return ""110}111}112
113if len(yamlPatch) != 0 {114return string(yamlPatch)115}116
117objContainers = append(objContainers, contToInsert)118
119withFantic := map[string]map[string][]interface{}{"spec": {"containers": objContainers}}120yamlPatch, err = yaml.Marshal(withFantic)121if err != nil {122return ""123}124
125return string(yamlPatch)126}
127
128func getPatchForVolume(specData interface{}, volName string, obj map[string]interface{}, strategy UpdateStrategy) []string {129spec, ok := specData.(map[string]interface{})["spec"]130if !ok {131return nil132}133volumes, ok := spec.(map[string]interface{})["volumes"]134if !ok {135return nil136}137
138var patches []string139
140for _, volToInsert := range volumes.([]interface{}) {141res, ok := volToInsert.(map[string]interface{})["name"]142if !ok || res != volName {143continue144}145
146if strategy == MergeStrategy {147patches = append(patches, getPatchForVolumeMergeStrategy(volToInsert.(map[string]interface{})))148}149if strategy == ReplaceStrategy {150patches = append(patches, getPatchForVolumeReplaceStrategy(volName, obj, volToInsert.(map[string]interface{})))151}152}153
154return patches155}
156
157func getPatchForVolumeMergeStrategy(volToInsert map[string]interface{}) string {158withFantic := map[string]map[string][]map[string]interface{}{"spec": {"volumes": {volToInsert}}}159yamlPatch, err := yaml.Marshal(withFantic)160if err != nil {161return ""162}163return string(yamlPatch)164}
165
166func getPatchForVolumeReplaceStrategy(volName string, obj, volToInsert map[string]interface{}) string {167objVols, err := jmespath.Search("spec.volumes", obj)168if err != nil || objVols == nil {169return ""170}171
172objVolumes, ok := objVols.([]interface{})173if !ok {174return ""175}176
177var yamlPatch []byte178
179for i := range objVolumes {180if objVolumes[i].(map[string]interface{})["name"] != volName {181continue182}183objVolumes[i] = volToInsert184withFantic := map[string]map[string][]interface{}{"spec": {"volumes": objVolumes}}185yamlPatch, err = yaml.Marshal(withFantic)186if err != nil {187return ""188}189
190}191
192if len(yamlPatch) != 0 {193return string(yamlPatch)194}195
196objVolumes = append(objVolumes, volToInsert)197
198withFantic := map[string]map[string][]interface{}{"spec": {"volumes": objVolumes}}199yamlPatch, err = yaml.Marshal(withFantic)200if err != nil {201return ""202}203return string(yamlPatch)204}
205
206func getPatchForAnnotation(specData interface{}, annName string) []string {207metadata, ok := specData.(map[string]interface{})["metadata"]208if !ok {209return nil210}211annots, ok := metadata.(map[string]interface{})["annotations"]212if !ok {213return nil214}215
216val, ok := annots.(map[string]interface{})[annName]217if !ok {218return nil219}220
221withFantic := map[string]map[string]map[string]interface{}{"metadata": {"annotations": {annName: val}}}222yamlPatch, err := yaml.Marshal(withFantic)223if err != nil {224return nil225}226
227return []string{string(yamlPatch)}228}
229
230func convert(i interface{}) interface{} {231switch x := i.(type) {232case map[interface{}]interface{}:233m2 := map[string]interface{}{}234for k, v := range x {235m2[k.(string)] = convert(v)236}237return m2238case []interface{}:239for i, v := range x {240x[i] = convert(v)241}242}243return i244}
245