В 22:00 МСК будет объявлен перерыв - 10 минут. Вы отдыхаете - мы обновляем!

kubelatte-ce

Форк от sbertech/kubelatte-ce
Форк
2
/
rendering.go 
246 строк · 8.5 Кб
1
package mutation
2

3
import (
4
	"context"
5
	"errors"
6
	"fmt"
7
	"github.com/gohobby/deepcopy"
8
	"gitverse.ru/synapse/kubelatte/pkg/api/common"
9
	"gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
10
	"gitverse.ru/synapse/kubelatte/pkg/observability/logger"
11
	"gitverse.ru/synapse/kubelatte/pkg/storage"
12
	"gitverse.ru/synapse/kubelatte/pkg/util"
13
	"gitverse.ru/synapse/kubelatte/pkg/util/match"
14
	"gitverse.ru/synapse/kubelatte/pkg/util/templates"
15
	"k8s.io/api/admission/v1beta1"
16
	"k8s.io/apimachinery/pkg/apis/meta/v1"
17
	"k8s.io/apimachinery/pkg/labels"
18
	"regexp"
19
	"sigs.k8s.io/yaml"
20
	"strings"
21
)
22

23
var ErrCheckMatchSelector = errors.New("err check match selector")
24

25
type MutRendererI interface {
26
	GetRenders(ctx context.Context, arfields *common.ARFields) []util.RenderItem
27
	GetRendersForMutatingConfig(ctx context.Context, arfields common.ARFields, config v1alpha1.MutationConfig, object ObjInfo, obj map[string]interface{}, templs map[string]v1alpha1.Template, renders []util.RenderItem) ([]util.RenderItem, error)
28
	ApplyTemplate(ctx context.Context, template v1alpha1.Template, obj map[string]interface{}, strategy string) []util.RenderItem
29
}
30

31
type MutRenderer struct {
32
	matcher match.MatcherI
33
	act     MutRendererI
34
}
35

36
func NewMutRenderer(matcher match.MatcherI, act MutRendererI) MutRendererI {
37
	renderer := &MutRenderer{matcher: matcher}
38
	if act == nil {
39
		act = renderer
40
	}
41
	renderer.act = act
42
	return renderer
43
}
44

45
func (r *MutRenderer) GetRenders(ctx context.Context, arfields *common.ARFields) []util.RenderItem {
46
	var renders []util.RenderItem
47
	triggers := storage.Storage.GetTriggers()
48

49
	for _, trigger := range triggers {
50
		renders = append(renders, r.getRendersForTrigger(ctx, trigger, *arfields)...)
51
	}
52
	return renders
53
}
54

55
func (r *MutRenderer) getRendersForTrigger(ctx context.Context, trigger v1alpha1.Trigger, arfields common.ARFields) []util.RenderItem {
56
	var renders []util.RenderItem
57
	var err error
58
	log := logger.FromContext(ctx)
59
	templs := storage.Storage.GetTemplates()
60
	obj := deepcopy.DeepCopy(arfields.Object).(map[string]interface{})
61
	object := getObjectInfoFromMap(obj)
62

63
	for _, config := range trigger.Spec.MutationConfigs {
64
		renders, err = r.act.GetRendersForMutatingConfig(ctx, arfields, config, object, obj, templs, renders)
65
		if err != nil {
66
			log.Debugf(err.Error())
67
		}
68
	}
69

70
	return renders
71
}
72

73
func (r *MutRenderer) GetRendersForMutatingConfig(ctx context.Context, arfields common.ARFields, config v1alpha1.MutationConfig, object ObjInfo, obj map[string]interface{}, templs map[string]v1alpha1.Template, renders []util.RenderItem,
74
) ([]util.RenderItem, error) {
75
	log := logger.FromContext(ctx)
76

77
	if matches, _ := r.matcher.Match(ctx, arfields, config.Match); !matches || arfields.Operation == v1beta1.Delete {
78
		return renders, fmt.Errorf("check mutation trigger %s match failed, %w", config.Name, match.ErrMatchFailed)
79
	}
80

81
	if config.Match.IsEmpty() && !r.checkMatchSelector(ctx, &config, object) {
82
		return renders, fmt.Errorf("check trigger %s checkMatchSelector failed, %w", config.Name, ErrCheckMatchSelector)
83
	}
84

85
	log.Debugf("Check trigger %s match selector ok", config.Name)
86

87
	if len(config.TemplateRefs) == 0 && object.Kind == "Pod" {
88
		renders = append(renders, r.getRendersForPod(ctx, templs, obj, config)...)
89
	}
90

91
	for _, ref := range config.TemplateRefs {
92
		if t, ok := templs[ref]; ok {
93
			renders = append(renders, r.act.ApplyTemplate(ctx, t, obj, config.UpdateStrategy)...)
94
		}
95
	}
96
	return renders, nil
97
}
98

99
// checkMatchSelector Need replaced to universal Match allow function
100
func (r *MutRenderer) checkMatchSelector(ctx context.Context, config *v1alpha1.MutationConfig, obj ObjInfo) bool {
101
	log := logger.FromContext(ctx)
102
	log.Debugf("checkMatchSelector got annotations %s, labels %s ", obj.annots, obj.labels)
103
	log.Debugf("checkMatchSelector ObjectSelector Kind %s, Name %s", obj.Kind, obj.name)
104
	if config.ObjectSelector.Kind != "" && config.ObjectSelector.Name != "" {
105
		if obj.Kind == config.ObjectSelector.Kind {
106
			matches, err := regexp.Match(config.ObjectSelector.Name, []byte(obj.name))
107
			if err != nil {
108
				log.Errorf("Mutator: checkMatchSelector failed %s", err.Error())
109
			}
110
			if matches {
111
				log.Debugf("checkMatchSelector ObjectSelector Kind %s, Name %s checked ok", obj.Kind, obj.name)
112
				return true
113
			}
114
		}
115
	}
116

117
	if obj.labels != nil && len(config.LabelSelector.MatchExpressions) != 0 {
118
		labelSet := labels.Set(obj.labels)
119
		labelSelectors := v1.LabelSelector{}
120

121
		for _, expression := range config.LabelSelector.MatchExpressions {
122

123
			labelSelectors.MatchExpressions = append(labelSelectors.MatchExpressions,
124
				v1.LabelSelectorRequirement{
125
					Key:      getSelectorKey(expression.Key, expression.Values),
126
					Operator: expression.Operator,
127
					Values:   expression.Values,
128
				},
129
			)
130

131
			sel, err := v1.LabelSelectorAsSelector(&labelSelectors)
132
			if err != nil {
133
				log.Errorf("Mutator: checkMatchSelector failed %s", err)
134
			} else {
135
				return sel.Matches(labelSet)
136
			}
137
		}
138
	}
139

140
	if obj.annots != nil {
141
		triggerKey := getSelectorKey(fmt.Sprintf("%s/%s", config.AnnotationNamespace, config.AnnotationTrigger), nil)
142
		triggerValue, ok := obj.annots[triggerKey]
143
		if ok {
144
			log.Debugf("checkMatchSelector Annotations annotation %s %s ok ", triggerKey, triggerValue)
145
			if triggerValue != "true" && triggerValue != "enabled" {
146
				log.Error("Mutator: checkMatchSelector failed skip creation cause annotation value is not valid")
147
			} else {
148
				return true
149
			}
150
		}
151
	}
152

153
	return false
154
}
155

156
func (r *MutRenderer) getRendersForPod(ctx context.Context, templs map[string]v1alpha1.Template,
157
	ob map[string]interface{}, config v1alpha1.MutationConfig) []util.RenderItem {
158
	log := logger.FromContext(ctx)
159
	obj := deepcopy.DeepCopy(ob).(map[string]interface{})
160

161
	var detailedData detailedRefTemplateObjectsData
162
	var renders []util.RenderItem
163
	strategy := UpdateStrategy(config.UpdateStrategy)
164

165
	log.Debugf("[getRendersForPod] config.Containers: %v, config.Annotations: %v, config.Volumes: %v",
166
		config.Containers, config.Annotations, config.Volumes)
167

168
	detailedData = prepareDataForUniversalMutation(config.Containers, config.Annotations, config.Volumes)
169

170
	renders = append(renders, r.cutAndApplyTemplate(ctx, detailedData.containers, templs, obj, "container", strategy)...)
171
	renders = append(renders, r.cutAndApplyTemplate(ctx, detailedData.annotations, templs, obj, "annotation", strategy)...)
172
	renders = append(renders, r.cutAndApplyTemplate(ctx, detailedData.volumes, templs, obj, "volume", strategy)...)
173

174
	for i, render := range renders {
175
		log.Debugf("render %v: %v\n", i, render)
176
	}
177

178
	return renders
179
}
180

181
func (r *MutRenderer) cutAndApplyTemplate(ctx context.Context, resource map[string][]string,
182
	templs map[string]v1alpha1.Template, obj map[string]interface{}, resourceType string, strategy UpdateStrategy) []util.RenderItem {
183
	log := logger.FromContext(ctx)
184
	var renders []util.RenderItem
185
	var patches []string
186

187
	for ref, names := range resource {
188
		templ, ok := templs[ref]
189
		if !ok {
190
			log.Debugf("There is no refs to %s, continue", ref)
191
			continue
192
		}
193

194
		rs := r.act.ApplyTemplate(ctx, templ, obj, string(strategy))
195
		if len(rs) == 0 {
196
			log.Error("Render is empty, nothing for mutate")
197
			continue
198
		}
199
		templ.Spec.Data = rs[0].Render
200

201
		var specData interface{}
202
		if err := yaml.Unmarshal([]byte(templ.Spec.Data), &specData); err != nil {
203
			log.Errorf("Converting templ.spec.data to yaml error: %s", err.Error())
204
			continue
205
		}
206

207
		specData = convert(specData)
208

209
		for _, name := range names {
210
			switch resourceType {
211
			case "container":
212
				patches = append(patches, getPatchForContainer(specData, name, obj, strategy)...)
213
			case "volume":
214
				patches = append(patches, getPatchForVolume(specData, name, obj, strategy)...)
215
			case "annotation":
216
				patches = append(patches, getPatchForAnnotation(specData, name)...)
217
			}
218
		}
219

220
		for _, patch := range patches {
221
			templ.Spec.Data = patch
222
			renders = append(renders, r.act.ApplyTemplate(ctx, templ, obj, string(strategy))...)
223
		}
224
	}
225

226
	return renders
227
}
228

229
func (r *MutRenderer) ApplyTemplate(ctx context.Context, template v1alpha1.Template, obj map[string]interface{}, strategy string) []util.RenderItem {
230
	log := logger.FromContext(ctx)
231
	var renders []util.RenderItem
232

233
	engine := templates.LoadTemplate(ctx, template)
234
	log.Debugf("loading tmpl %v, %v", template.Name, template.Spec.Data)
235
	for _, engineTemplate := range engine.Templates() {
236
		log.Debugf("template %v", engineTemplate.Name())
237
		var tempBuffer strings.Builder
238
		err := engineTemplate.Execute(&tempBuffer, obj)
239
		if err != nil {
240
			log.Errorf("Mutator: getRenders failed %s", err.Error())
241
			continue
242
		}
243
		renders = append(renders, util.RenderItem{Template: template, Render: tempBuffer.String(), Action: strategy})
244
	}
245
	return renders
246
}
247

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

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

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

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