kubelatte-ce

Форк
2
Форк от sbertech/kubelatte-ce
435 строк · 13.1 Кб
1
package templates
2

3
import (
4
	"context"
5
	"fmt"
6
	"github.com/Masterminds/sprig/v3"
7
	"github.com/gohobby/deepcopy"
8
	"gitverse.ru/synapse/kubelatte/pkg/api/v1alpha1"
9
	"gitverse.ru/synapse/kubelatte/pkg/observability/logger"
10
	"sigs.k8s.io/yaml"
11
	"strings"
12
	"text/template"
13
)
14

15
func LoadTemplate(ctx context.Context, ts ...v1alpha1.Template) *template.Template {
16
	log := logger.FromContext(ctx)
17
	templateEngine := template.New("common").
18
		Delims("{{%", "%}}").
19
		Funcs(GomplateFuncs).
20
		Funcs(sprig.TxtFuncMap())
21
	for _, t := range ts {
22
		_, err := templateEngine.New(t.Name).Parse(t.Spec.Data)
23
		if err != nil {
24
			log.Errorf("LoadTemplate failed %s", err.Error())
25
			return nil
26
		}
27
	}
28
	return templateEngine
29
}
30

31
var GomplateFuncs = template.FuncMap{
32
	"del":                    Del,
33
	"toYaml":                 ToYAML,
34
	"indent":                 Indent,
35
	"nindent":                Nindent,
36
	"fromYaml":               FromYAML,
37
	"replaceKey":             ReplaceKey,
38
	"OTTconfigPatchesToV3":   OTTconfigPatchesToV3,
39
	"RBACconfigPatchesToV3":  ConfigPatchesRBACToV3,
40
	"RateLimiterPatchesToV3": RateLimiterPatchesToV3,
41
}
42

43
// FromYAML decodes a YAML string into an interface{}. This allows injection templates to access
44
// configs defined as YAML strings.
45
func FromYAML(in string) (interface{}, error) {
46
	var out interface{}
47

48
	if err := yaml.Unmarshal([]byte(in), &out); err != nil {
49
		return nil, fmt.Errorf("failed to unmarshal yaml with error: %v. source: %q", err, in)
50
	}
51
	return out, nil
52
}
53

54
// ToYAML encodes an interface{} into a YAML string.
55
func ToYAML(in interface{}) (string, error) {
56
	out, err := yaml.Marshal(in)
57
	if err != nil {
58
		return "", fmt.Errorf("failed to unmarshal yaml with error: %v. source: %q", err, out)
59
	}
60
	if in == nil {
61
		out = []byte{}
62
	}
63

64
	return string(out), nil
65
}
66

67
func Indent(in string, spacesNum int) string {
68
	spaces := strings.Repeat(" ", spacesNum)
69
	out := strings.Replace(in, "\n", "\n"+spaces, -1) // nolint:gocritic
70
	return out + "\n"
71
}
72

73
func Nindent(in string, spacesNum int) string {
74
	out := "\n" + in
75
	return Indent(out, spacesNum)
76
}
77

78
func ReplaceKey(oldK, newKey string, in any) any {
79
	log := logger.FromContext(context.Background())
80
	oldKeyPath := strings.Split(oldK, ".")
81
	tmp := in
82

83
	for i, key := range oldKeyPath {
84
		tmpMap, ok := tmp.(map[string]any)
85
		if !ok {
86
			log.Debugf("ReplaceKey: can not assign to map %v", in)
87
			return in
88
		}
89

90
		tmp = tmpMap[key]
91

92
		if i == len(oldKeyPath)-1 {
93
			v, ok := tmpMap[key]
94
			if !ok {
95
				return in
96
			}
97

98
			delete(tmpMap, key)
99
			tmpMap[newKey] = v
100
			log.Debugf("ReplaceKey executed: %v -> %v", key, newKey)
101
		}
102
	}
103

104
	return in
105
}
106

107
// Del go template func. Deleting key from map
108
func Del(path string, obj any) any {
109
	log := logger.FromContext(context.Background())
110
	pathToDelete := strings.Split(path, ".")
111
	tmp := obj
112

113
	for i, key := range pathToDelete {
114
		tmpMap, ok := tmp.(map[string]any)
115
		if !ok {
116
			log.Debugf("Del: can not assign to map %v", obj)
117
			return obj
118
		}
119

120
		tmp = tmpMap[key]
121

122
		if i == len(pathToDelete)-1 {
123
			_, ok := tmpMap[key]
124
			if !ok {
125
				log.Debug("Del: key was not deleted")
126
				return obj
127
			}
128
			delete(tmpMap, key)
129
			log.Debugf("Del: key %v was deleted", key)
130
		}
131
	}
132

133
	return obj
134
}
135

136
func RateLimiterPatchesToV3(in interface{}) (interface{}, error) {
137
	copy := deepcopy.DeepCopy(in)
138
	copy, err := replaceFilterChainName(copy)
139
	if err != nil {
140
		return ToYAML(in)
141
	}
142
	copy, err = replaceLimiterTypedConfig(copy)
143
	if err != nil {
144
		return ToYAML(in)
145
	}
146
	return ToYAML(copy)
147
}
148
func OTTconfigPatchesToV3(in interface{}) (interface{}, error) {
149
	copy := deepcopy.DeepCopy(in)
150
	copy, err := replaceFilterChainName(copy)
151
	if err != nil {
152
		return ToYAML(in)
153
	}
154
	copy, err = replaceOTTTypedConfig(copy)
155
	if err != nil {
156
		return ToYAML(in)
157
	}
158

159
	return ToYAML(copy)
160
}
161

162
func replaceLimiterTypedConfig(in interface{}) (interface{}, error) {
163
	_, ok := in.(map[string]interface{})
164
	if !ok {
165
		return nil, fmt.Errorf("cant get value from yaml, check syntax")
166
	}
167
	patch, ok := in.(map[string]interface{})["patch"]
168
	if !ok {
169
		return nil, fmt.Errorf("cant get patch field")
170
	}
171
	_, ok = patch.(map[string]interface{})
172
	if !ok {
173
		return nil, fmt.Errorf("patch is not a map check syntax")
174
	}
175
	value, ok := patch.(map[string]interface{})["value"]
176
	if !ok {
177
		return nil, fmt.Errorf("cant get patch.value field")
178
	}
179
	_, ok = value.(map[string]interface{})
180
	if !ok {
181
		return nil, fmt.Errorf("value is not a map check syntax")
182
	}
183
	config, ok := value.(map[string]interface{})["config"]
184
	if !ok {
185
		return nil, fmt.Errorf("cant get patch.value.config field")
186
	}
187
	_, ok = config.(map[string]interface{})
188
	if !ok {
189
		return nil, fmt.Errorf("value is not a map check syntax")
190
	}
191
	rate_limit_service, ok := config.(map[string]interface{})["rate_limit_service"]
192
	if !ok {
193
		return nil, fmt.Errorf("cant get patch.value.config.rate_limit_service field")
194
	}
195
	_, ok = rate_limit_service.(map[string]interface{})
196
	if !ok {
197
		return nil, fmt.Errorf("patch.value.config.rate_limit_service field is not a map")
198
	}
199
	rate_limit_service.(map[string]interface{})["transport_api_version"] = "V3"
200

201
	value.(map[string]interface{})["typed_config"] = config
202
	value.(map[string]interface{})["typed_config"].(map[string]interface{})["@type"] = "type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit"
203
	delete(value.(map[string]interface{}), "config")
204

205
	return in, nil
206

207
}
208
func replaceOTTTypedConfig(in interface{}) (interface{}, error) {
209
	_, ok := in.(map[string]interface{})
210
	if !ok {
211
		return nil, fmt.Errorf("cant get value from yaml, check syntax")
212
	}
213
	patch, ok := in.(map[string]interface{})["patch"]
214
	if !ok {
215
		return nil, fmt.Errorf("cant get patch field")
216
	}
217
	_, ok = patch.(map[string]interface{})
218
	if !ok {
219
		return nil, fmt.Errorf("patch is not a map check syntax")
220
	}
221
	value, ok := patch.(map[string]interface{})["value"]
222
	if !ok {
223
		return nil, fmt.Errorf("cant get patch.value field")
224
	}
225
	_, ok = value.(map[string]interface{})
226
	if !ok {
227
		return nil, fmt.Errorf("value is not a map check syntax")
228
	}
229
	config, ok := value.(map[string]interface{})["config"]
230
	if !ok {
231
		return nil, fmt.Errorf("cant get patch.value.config field")
232
	}
233
	_, ok = config.(map[string]interface{})
234
	if !ok {
235
		return nil, fmt.Errorf("value is not a map check syntax")
236
	}
237
	config.(map[string]interface{})["transport_api_version"] = "V3"
238
	grpcService, ok := config.(map[string]interface{})["grpc_service"]
239
	if !ok {
240
		return nil, fmt.Errorf("cant get patch.value.config.grpc_service field")
241
	}
242
	_, ok = grpcService.(map[string]interface{})
243
	if !ok {
244
		return nil, fmt.Errorf("value is not a map check syntax")
245
	}
246
	googleGrpc, ok := grpcService.(map[string]interface{})["google_grpc"]
247
	if !ok {
248
		return nil, fmt.Errorf("cant get patch.value.config.grpc_service.google_grpc field")
249
	}
250
	_, ok = googleGrpc.(map[string]interface{})
251
	if !ok {
252
		return nil, fmt.Errorf("value is not a map check syntax")
253
	}
254
	statPrefix, ok := googleGrpc.(map[string]interface{})["stat_prefix"]
255
	if !ok {
256
		return nil, fmt.Errorf("cant get patch.value.config.grpc_service.google_grpc.stat_prefix field")
257
	}
258
	switch statPrefix {
259
	case "ext_authz":
260
		value.(map[string]interface{})["typed_config"] = config
261
		value.(map[string]interface{})["typed_config"].(map[string]interface{})["@type"] = "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz"
262
		delete(value.(map[string]interface{}), "config")
263
	case "sbt_authz":
264
		value.(map[string]interface{})["typed_config"] = make(map[string]interface{})
265
		value.(map[string]interface{})["typed_config"].(map[string]interface{})["value"] = config
266
		typedValue := value.(map[string]interface{})["typed_config"].(map[string]interface{})["value"]
267
		typedValue.(map[string]interface{})["api"] = "STANDART"
268
		value.(map[string]interface{})["typed_config"].(map[string]interface{})["@type"] = "type.googleapis.com/udpa.type.v1.TypedStruct"
269
		value.(map[string]interface{})["typed_config"].(map[string]interface{})["typeUrl"] = "type.googleapis.com/envoy.extensions.filters.http.sbt_authz.v3.SbtAuthz"
270
		delete(value.(map[string]interface{}), "config")
271
	default:
272
		return nil, fmt.Errorf("stat_prefix is not supported")
273
	}
274

275
	return in, nil
276
}
277

278
func ConfigPatchesRBACToV3(in interface{}) (interface{}, error) {
279
	copy := deepcopy.DeepCopy(in)
280
	copy, err := replaceFilterChainName(copy)
281
	if err != nil {
282
		return ToYAML(in)
283
	}
284
	copy, err = replaceRBACTypedConfig(copy, "type.googleapis.com/envoy.extensions.filters.http.rbac.v3.RBAC")
285
	if err != nil {
286
		return ToYAML(in)
287
	}
288

289
	return ToYAML(copy)
290
}
291

292
func replaceRBACTypedConfig(in interface{}, filterType string) (interface{}, error) {
293
	_, ok := in.(map[string]interface{})
294
	if !ok {
295
		return nil, fmt.Errorf("cant get value from yaml, check syntax")
296
	}
297
	patch, ok := in.(map[string]interface{})["patch"]
298
	if !ok {
299
		return nil, fmt.Errorf("cant get patch field")
300
	}
301
	_, ok = patch.(map[string]interface{})
302
	if !ok {
303
		return nil, fmt.Errorf("patch is not a map check syntax")
304
	}
305
	value, ok := patch.(map[string]interface{})["value"]
306
	if !ok {
307
		return nil, fmt.Errorf("cant get patch.value field")
308
	}
309
	_, ok = value.(map[string]interface{})
310
	if !ok {
311
		return nil, fmt.Errorf("value is not a map check syntax")
312
	}
313
	config, ok := value.(map[string]interface{})["config"]
314
	if !ok {
315
		return nil, fmt.Errorf("cant get patch.value.config field")
316
	}
317
	value.(map[string]interface{})["typed_config"] = config
318
	value.(map[string]interface{})["typed_config"].(map[string]interface{})["@type"] = filterType
319
	delete(value.(map[string]interface{}), "config")
320

321
	typedConfig := value.(map[string]interface{})["typed_config"]
322

323
	rules, ok := typedConfig.(map[string]interface{})["rules"]
324
	if !ok {
325
		return nil, fmt.Errorf("cant get patch.value.config.rules field")
326
	}
327
	if _, ok = rules.(map[string]interface{}); !ok {
328
		return nil, fmt.Errorf("rules is not a map, check syntax")
329
	}
330
	policies, ok := rules.(map[string]interface{})["policies"]
331
	if !ok {
332
		return nil, fmt.Errorf("cant get patch.value.config.rules.policies field")
333
	}
334
	if _, ok = policies.(map[string]interface{}); !ok {
335
		return nil, fmt.Errorf("policies is not a map, check syntax")
336
	}
337
	for k, v := range policies.(map[string]interface{}) {
338
		if _, ok = v.(map[string]interface{}); !ok {
339
			return nil, fmt.Errorf("%v is not a map, check syntax", k)
340
		}
341
		permissions, ok := v.(map[string]interface{})["permissions"]
342
		if !ok {
343
			return nil, fmt.Errorf("cant get patch.value.config.rules.policies.%v.permissions field", k)
344
		}
345
		if _, ok = permissions.([]interface{}); !ok {
346
			if _, ok = permissions.(map[string]interface{}); !ok {
347
				return nil, fmt.Errorf("permissions is not a map, check syntax")
348
			}
349
			var perms []interface{}
350
			for perm_key, perm_value := range permissions.(map[string]interface{}) {
351
				permMap := make(map[string]interface{})
352
				permMap[perm_key] = perm_value
353
				perms = append(perms, permMap)
354
			}
355
			policies.(map[string]interface{})[k].(map[string]interface{})["permissions"] = perms
356
		}
357
		principals, ok := v.(map[string]interface{})["principals"]
358
		if !ok {
359
			return nil, fmt.Errorf("cant get patch.value.config.rules.policies.%v.principals field", k)
360
		}
361
		if _, ok = principals.([]interface{}); !ok {
362
			if _, ok = principals.(map[string]interface{}); !ok {
363
				return nil, fmt.Errorf("principals is not a map, check syntax")
364
			}
365
			var princ []interface{}
366
			for pr_key, pr_value := range principals.(map[string]interface{}) {
367
				permMap := make(map[string]interface{})
368
				permMap[pr_key] = pr_value
369
				princ = append(princ, permMap)
370
			}
371
			policies.(map[string]interface{})[k].(map[string]interface{})["principals"] = princ
372
		}
373
	}
374
	return in, nil
375

376
}
377

378
func replaceFilterChainName(out interface{}) (interface{}, error) {
379
	_, ok := out.(map[string]interface{})
380
	if !ok {
381
		return out, fmt.Errorf("cant get value from yaml, check syntax")
382
	}
383
	match, ok := out.(map[string]interface{})["match"]
384
	if !ok {
385
		return out, fmt.Errorf("cant get match field")
386
	}
387
	_, ok = match.(map[string]interface{})
388
	if !ok {
389
		return out, fmt.Errorf("match is not a map check syntax")
390
	}
391
	listener, ok := match.(map[string]interface{})["listener"]
392
	if !ok {
393
		return out, fmt.Errorf("cant get match.listener field")
394
	}
395
	_, ok = listener.(map[string]interface{})
396
	if !ok {
397
		return out, fmt.Errorf("listener is not a map, check syntax")
398
	}
399
	filterChain, ok := listener.(map[string]interface{})["filterChain"]
400
	if !ok {
401
		return out, fmt.Errorf("cant get match.listener.filterChain field")
402
	}
403
	_, ok = filterChain.(map[string]interface{})
404
	if !ok {
405
		return out, fmt.Errorf("filterChain is not a map, check syntax")
406
	}
407
	filter, ok := filterChain.(map[string]interface{})["filter"]
408
	if !ok {
409
		return out, fmt.Errorf("cant get match.listener.filterChain.filter field")
410
	}
411
	_, ok = filter.(map[string]interface{})
412
	if !ok {
413
		return out, fmt.Errorf("filter is not a map, check syntax")
414
	}
415
	_, ok = filter.(map[string]interface{})["name"]
416
	if !ok {
417
		return out, fmt.Errorf("cant get match.listener.filterChain.filter.name field")
418
	}
419
	filter.(map[string]interface{})["name"] = "envoy.filters.network.http_connection_manager"
420
	if subfilter, ok := filter.(map[string]interface{})["subFilter"]; ok {
421
		if _, ok = subfilter.(map[string]interface{}); !ok {
422
			return out, nil
423
		}
424
		name, ok := subfilter.(map[string]interface{})["name"]
425
		if !ok {
426
			return out, nil
427
		}
428
		if name == "envoy.router" {
429
			subfilter.(map[string]interface{})["name"] = "envoy.filters.http.router"
430
		}
431

432
		return out, nil
433
	}
434
	return out, nil
435
}
436

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

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

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

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