istio

Форк
0
259 строк · 8.0 Кб
1
// Copyright Istio Authors
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14

15
package helm
16

17
import (
18
	"fmt"
19
	"os"
20
	"path/filepath"
21
	"sort"
22
	"strconv"
23
	"strings"
24

25
	"helm.sh/helm/v3/pkg/chart"
26
	"helm.sh/helm/v3/pkg/chartutil"
27
	"helm.sh/helm/v3/pkg/engine"
28
	"k8s.io/apimachinery/pkg/version"
29
	"sigs.k8s.io/yaml"
30

31
	"istio.io/istio/istioctl/pkg/install/k8sversion"
32
	"istio.io/istio/manifests"
33
	"istio.io/istio/operator/pkg/util"
34
	"istio.io/istio/pkg/log"
35
)
36

37
const (
38
	// YAMLSeparator is a separator for multi-document YAML files.
39
	YAMLSeparator = "\n---\n"
40

41
	// DefaultProfileString is the name of the default profile.
42
	DefaultProfileString = "default"
43

44
	// NotesFileNameSuffix is the file name suffix for helm notes.
45
	// see https://helm.sh/docs/chart_template_guide/notes_files/
46
	NotesFileNameSuffix = ".txt"
47
)
48

49
var scope = log.RegisterScope("installer", "installer")
50

51
// TemplateFilterFunc filters templates to render by their file name
52
type TemplateFilterFunc func(string) bool
53

54
// TemplateRenderer defines a helm template renderer interface.
55
type TemplateRenderer interface {
56
	// Run starts the renderer and should be called before using it.
57
	Run() error
58
	// RenderManifest renders the associated helm charts with the given values YAML string and returns the resulting
59
	// string.
60
	RenderManifest(values string) (string, error)
61
	// RenderManifestFiltered filters manifests to render by template file name
62
	RenderManifestFiltered(values string, filter TemplateFilterFunc) (string, error)
63
}
64

65
// NewHelmRenderer creates a new helm renderer with the given parameters and returns an interface to it.
66
// The format of helmBaseDir and profile strings determines the type of helm renderer returned (compiled-in, file,
67
// HTTP etc.)
68
func NewHelmRenderer(operatorDataDir, helmSubdir, componentName, namespace string, version *version.Info) TemplateRenderer {
69
	dir := strings.Join([]string{ChartsSubdirName, helmSubdir}, "/")
70
	return NewGenericRenderer(manifests.BuiltinOrDir(operatorDataDir), dir, componentName, namespace, version)
71
}
72

73
// ReadProfileYAML reads the YAML values associated with the given profile. It uses an appropriate reader for the
74
// profile format (compiled-in, file, HTTP, etc.).
75
func ReadProfileYAML(profile, manifestsPath string) (string, error) {
76
	var err error
77
	var globalValues string
78

79
	// Get global values from profile.
80
	switch {
81
	case util.IsFilePath(profile):
82
		if globalValues, err = readFile(profile); err != nil {
83
			return "", err
84
		}
85
	default:
86
		if globalValues, err = LoadValues(profile, manifestsPath); err != nil {
87
			return "", fmt.Errorf("failed to read profile %v from %v: %v", profile, manifestsPath, err)
88
		}
89
	}
90

91
	return globalValues, nil
92
}
93

94
// renderChart renders the given chart with the given values and returns the resulting YAML manifest string.
95
func renderChart(namespace, values string, chrt *chart.Chart, filterFunc TemplateFilterFunc, version *version.Info) (string, error) {
96
	options := chartutil.ReleaseOptions{
97
		Name:      "istio",
98
		Namespace: namespace,
99
	}
100
	valuesMap := map[string]any{}
101
	if err := yaml.Unmarshal([]byte(values), &valuesMap); err != nil {
102
		return "", fmt.Errorf("failed to unmarshal values: %v", err)
103
	}
104

105
	caps := *chartutil.DefaultCapabilities
106

107
	// overwrite helm default capabilities
108
	operatorVersion, _ := chartutil.ParseKubeVersion("1." + strconv.Itoa(k8sversion.MinK8SVersion) + ".0")
109
	caps.KubeVersion = *operatorVersion
110

111
	if version != nil {
112
		caps.KubeVersion = chartutil.KubeVersion{
113
			Version: version.GitVersion,
114
			Major:   version.Major,
115
			Minor:   version.Minor,
116
		}
117
	}
118
	vals, err := chartutil.ToRenderValues(chrt, valuesMap, options, &caps)
119
	if err != nil {
120
		return "", err
121
	}
122

123
	if filterFunc != nil {
124
		filteredTemplates := []*chart.File{}
125
		for _, t := range chrt.Templates {
126
			// Always include required templates that do not produce any output
127
			if filterFunc(t.Name) || strings.HasSuffix(t.Name, ".tpl") || t.Name == "templates/zzz_profile.yaml" {
128
				filteredTemplates = append(filteredTemplates, t)
129
			}
130
		}
131
		chrt.Templates = filteredTemplates
132
	}
133

134
	files, err := engine.Render(chrt, vals)
135
	crdFiles := chrt.CRDObjects()
136
	if err != nil {
137
		return "", err
138
	}
139
	if chrt.Metadata.Name == "base" {
140
		base, _ := valuesMap["base"].(map[string]any)
141
		if enableIstioConfigCRDs, ok := base["enableIstioConfigCRDs"].(bool); ok && !enableIstioConfigCRDs {
142
			crdFiles = []chart.CRD{}
143
		}
144
	}
145

146
	// Create sorted array of keys to iterate over, to stabilize the order of the rendered templates
147
	keys := make([]string, 0, len(files))
148
	for k := range files {
149
		if strings.HasSuffix(k, NotesFileNameSuffix) {
150
			continue
151
		}
152
		keys = append(keys, k)
153
	}
154
	sort.Strings(keys)
155

156
	var sb strings.Builder
157
	for i := 0; i < len(keys); i++ {
158
		f := files[keys[i]]
159
		// add yaml separator if the rendered file doesn't have one at the end
160
		f = strings.TrimSpace(f) + "\n"
161
		if !strings.HasSuffix(f, YAMLSeparator) {
162
			f += YAMLSeparator
163
		}
164
		_, err := sb.WriteString(f)
165
		if err != nil {
166
			return "", err
167
		}
168
	}
169

170
	// Sort crd files by name to ensure stable manifest output
171
	sort.Slice(crdFiles, func(i, j int) bool { return crdFiles[i].Name < crdFiles[j].Name })
172
	for _, crdFile := range crdFiles {
173
		f := string(crdFile.File.Data)
174
		// add yaml separator if the rendered file doesn't have one at the end
175
		f = strings.TrimSpace(f) + "\n"
176
		if !strings.HasSuffix(f, YAMLSeparator) {
177
			f += YAMLSeparator
178
		}
179
		_, err := sb.WriteString(f)
180
		if err != nil {
181
			return "", err
182
		}
183
	}
184

185
	return sb.String(), nil
186
}
187

188
// GenerateHubTagOverlay creates an IstioOperatorSpec overlay YAML for hub and tag.
189
func GenerateHubTagOverlay(hub, tag string) (string, error) {
190
	hubTagYAMLTemplate := `
191
spec:
192
  hub: {{.Hub}}
193
  tag: {{.Tag}}
194
`
195
	ts := struct {
196
		Hub string
197
		Tag string
198
	}{
199
		Hub: hub,
200
		Tag: tag,
201
	}
202
	return util.RenderTemplate(hubTagYAMLTemplate, ts)
203
}
204

205
// DefaultFilenameForProfile returns the profile name of the default profile for the given profile.
206
func DefaultFilenameForProfile(profile string) string {
207
	switch {
208
	case util.IsFilePath(profile):
209
		return filepath.Join(filepath.Dir(profile), DefaultProfileFilename)
210
	default:
211
		return DefaultProfileString
212
	}
213
}
214

215
// IsDefaultProfile reports whether the given profile is the default profile.
216
func IsDefaultProfile(profile string) bool {
217
	return profile == "" || profile == DefaultProfileString || filepath.Base(profile) == DefaultProfileFilename
218
}
219

220
func readFile(path string) (string, error) {
221
	b, err := os.ReadFile(path)
222
	return string(b), err
223
}
224

225
// GetProfileYAML returns the YAML for the given profile name, using the given profileOrPath string, which may be either
226
// a profile label or a file path.
227
func GetProfileYAML(installPackagePath, profileOrPath string) (string, error) {
228
	if profileOrPath == "" {
229
		profileOrPath = "default"
230
	}
231
	profiles, err := readProfiles(installPackagePath)
232
	if err != nil {
233
		return "", fmt.Errorf("failed to read profiles: %v", err)
234
	}
235
	// If charts are a file path and profile is a name like default, transform it to the file path.
236
	if profiles[profileOrPath] && installPackagePath != "" {
237
		profileOrPath = filepath.Join(installPackagePath, "profiles", profileOrPath+".yaml")
238
	}
239
	// This contains the IstioOperator CR.
240
	baseCRYAML, err := ReadProfileYAML(profileOrPath, installPackagePath)
241
	if err != nil {
242
		return "", err
243
	}
244

245
	if !IsDefaultProfile(profileOrPath) {
246
		// Profile definitions are relative to the default profileOrPath, so read that first.
247
		dfn := DefaultFilenameForProfile(profileOrPath)
248
		defaultYAML, err := ReadProfileYAML(dfn, installPackagePath)
249
		if err != nil {
250
			return "", err
251
		}
252
		baseCRYAML, err = util.OverlayIOP(defaultYAML, baseCRYAML)
253
		if err != nil {
254
			return "", err
255
		}
256
	}
257

258
	return baseCRYAML, nil
259
}
260

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

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

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

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