istio

Форк
0
305 строк · 9.3 Кб
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 config
16

17
import (
18
	"encoding/json"
19
	"errors"
20
	"fmt"
21
	"math"
22
	"strings"
23
	"time"
24
)
25

26
type ResourceType int
27

28
const (
29
	Namespace ResourceType = iota
30
	Deployment
31
	Pod
32
	Label
33
	Annotation
34
	Container
35
)
36

37
// SelectionSpec is a spec for pods that will be Include in the capture
38
// archive. The format is:
39
//
40
//	Namespace1,Namespace2../Deployments/Pods/Label1,Label2.../Annotation1,Annotation2.../ContainerName1,ContainerName2...
41
//
42
// Namespace, pod and container names are pattern matching while labels
43
// and annotations may have pattern in the values with exact match for keys.
44
// All labels and annotations in the list must match.
45
// All fields are optional, if they are not specified, all values match.
46
// Pattern matching style is glob.
47
// Exclusions have a higher precedence than inclusions.
48
// Ordering defines pod priority for cases where the archive exceeds the maximum
49
// size and some logs must be dropped.
50
//
51
// Examples:
52
//
53
// 1. All pods in test-namespace with label "test=foo" but without label "private" (with any value):
54
//
55
//	include:
56
//	  test-namespace/*/*/test=foo
57
//	exclude:
58
//	  test-namespace/*/*/private
59
//
60
// 2. Pods in all namespaces except "kube-system" with annotation "revision"
61
// matching wildcard 1.6*:
62
//
63
//	exclude:
64
//	  kube-system/*/*/*/revision=1.6*
65
//
66
// 3. Pods with "prometheus" in the name, except those with
67
// the annotation "internal=true":
68
//
69
//	include:
70
//	  */*/*prometheus*
71
//	exclude:
72
//	  */*/*prometheus*/*/internal=true
73
//
74
// 4. Container logs for all containers called "istio-proxy":
75
//
76
//	include:
77
//	  */*/*/*/*/istio-proxy
78
type SelectionSpec struct {
79
	Namespaces  []string          `json:"namespaces,omitempty"`
80
	Deployments []string          `json:"deployments,omitempty"`
81
	Daemonsets  []string          `json:"daemonsets,omitempty"`
82
	Pods        []string          `json:"pods,omitempty"`
83
	Containers  []string          `json:"containers,omitempty"`
84
	Labels      map[string]string `json:"labels,omitempty"`
85
	Annotations map[string]string `json:"annotations,omitempty"`
86
}
87

88
type SelectionSpecs []*SelectionSpec
89

90
func (s SelectionSpecs) String() string {
91
	var out []string
92
	for _, ss := range s {
93
		st := ""
94
		if !defaultListSetting(ss.Namespaces) {
95
			st += fmt.Sprintf("Namespaces: %s", strings.Join(ss.Namespaces, ","))
96
		}
97
		if !defaultListSetting(ss.Deployments) {
98
			st += fmt.Sprintf("/Deployments: %s", strings.Join(ss.Deployments, ","))
99
		}
100
		if !defaultListSetting(ss.Pods) {
101
			st += fmt.Sprintf("/Pods:%s", strings.Join(ss.Pods, ","))
102
		}
103
		if !defaultListSetting(ss.Containers) {
104
			st += fmt.Sprintf("/Containers: %s", strings.Join(ss.Containers, ","))
105
		}
106
		if len(ss.Labels) > 0 {
107
			st += fmt.Sprintf("/Labels: %v", ss.Labels)
108
		}
109
		if len(ss.Annotations) > 0 {
110
			st += fmt.Sprintf("/Annotations: %v", ss.Annotations)
111
		}
112
		out = append(out, "{ "+st+" }")
113
	}
114
	return strings.Join(out, " AND ")
115
}
116

117
func defaultListSetting(s []string) bool {
118
	if len(s) < 1 {
119
		return true
120
	}
121
	if len(s) == 1 {
122
		return strings.TrimSpace(s[0]) == "" || s[0] == "*"
123
	}
124
	return false
125
}
126

127
// BugReportConfig controls what is captured and Include in the kube-capture tool
128
// archive.
129
type BugReportConfig struct {
130
	// KubeConfigPath is the path to kube config file.
131
	KubeConfigPath string `json:"kubeConfigPath,omitempty"`
132
	// Context is the cluster Context in the kube config
133
	Context string `json:"context,omitempty"`
134

135
	// IstioNamespace is the namespace where the istio control plane is installed.
136
	IstioNamespace string `json:"istioNamespace,omitempty"`
137

138
	// DryRun controls whether logs are actually captured and saved.
139
	DryRun bool `json:"dryRun,omitempty"`
140

141
	// FullSecrets controls whether secret contents are included.
142
	FullSecrets bool `json:"fullSecrets,omitempty"`
143

144
	// CommandTimeout is the maximum amount of time running the command
145
	// before giving up, even if not all logs are captured. Upon timeout,
146
	// the command creates an archive with only the logs captured so far.
147
	CommandTimeout Duration `json:"commandTimeout,omitempty"`
148

149
	// Include is a list of SelectionSpec entries for resources to include.
150
	Include SelectionSpecs `json:"include,omitempty"`
151
	// Exclude is a list of SelectionSpec entries for resources t0 exclude.
152
	Exclude SelectionSpecs `json:"exclude,omitempty"`
153

154
	// StartTime is the start time the log capture time range.
155
	// If set, Since must be unset.
156
	StartTime time.Time `json:"startTime,omitempty"`
157
	// EndTime is the end time the log capture time range.
158
	// Default is now.
159
	EndTime time.Time `json:"endTime,omitempty"`
160
	// Since defines the start time the log capture time range.
161
	// StartTime is set to EndTime - Since.
162
	// If set, StartTime must be unset.
163
	Since Duration `json:"since,omitempty"`
164

165
	// TimeFilterApplied stores if user has provided any time filtering flags.
166
	// If Since, StartTime, EndTime are all not applied by the user, set TimeFilterApplied as false; Otherwise set true
167
	TimeFilterApplied bool `json:"timeFilterApplied,omitempty"`
168

169
	// CriticalErrors is a list of glob pattern matches for errors that,
170
	// if found in a log, set the highest priority for the log to ensure
171
	// that it is Include in the capture archive.
172
	CriticalErrors []string `json:"criticalErrors,omitempty"`
173
	// IgnoredErrors are glob error patterns which are ignored when
174
	// calculating the error heuristic for a log.
175
	IgnoredErrors []string `json:"ignoredErrors,omitempty"`
176

177
	// RequestConcurrency controls the request concurrency limit to the API server.
178
	RequestConcurrency int `json:"requestConcurrency,omitempty"`
179
}
180

181
func (b *BugReportConfig) String() string {
182
	out := ""
183
	if b.KubeConfigPath != "" {
184
		out += fmt.Sprintf("kubeconfig: %s\n", b.KubeConfigPath)
185
	}
186
	if b.Context != "" {
187
		out += fmt.Sprintf("context: %s\n", b.Context)
188
	}
189
	out += fmt.Sprintf("istio-namespace: %s\n", b.IstioNamespace)
190
	out += fmt.Sprintf("full-secrets: %v\n", b.FullSecrets)
191
	out += fmt.Sprintf("timeout (mins): %v\n", math.Round(float64(int(b.CommandTimeout))/float64(time.Minute)))
192
	out += fmt.Sprintf("include: %s\n", b.Include)
193
	out += fmt.Sprintf("exclude: %s\n", b.Exclude)
194
	if !b.StartTime.Equal(time.Time{}) {
195
		out += fmt.Sprintf("start-time: %v\n", b.StartTime)
196
	}
197
	out += fmt.Sprintf("end-time: %v\n", b.EndTime)
198
	if b.Since != 0 {
199
		out += fmt.Sprintf("since: %v\n", b.Since)
200
	}
201
	return out
202
}
203

204
func parseToIncludeTypeSlice(s string) []string {
205
	if strings.TrimSpace(s) == "*" || s == "" {
206
		return nil
207
	}
208
	return strings.Split(s, ",")
209
}
210

211
func parseToIncludeTypeMap(s string) (map[string]string, error) {
212
	if strings.TrimSpace(s) == "*" {
213
		return nil, nil
214
	}
215
	out := make(map[string]string)
216
	for _, ss := range strings.Split(s, ",") {
217
		if len(ss) == 0 {
218
			continue
219
		}
220
		kv := strings.Split(ss, "=")
221
		if len(kv) != 2 {
222
			return nil, fmt.Errorf("bad label/annotation selection %s, must have format key=value", ss)
223
		}
224
		if strings.Contains(kv[0], "*") {
225
			return nil, fmt.Errorf("bad label/annotation selection %s, key cannot have '*' wildcards", ss)
226
		}
227
		out[kv[0]] = kv[1]
228
	}
229
	return out, nil
230
}
231

232
func (s *SelectionSpec) UnmarshalJSON(b []byte) error {
233
	ft := []ResourceType{Namespace, Deployment, Pod, Label, Annotation, Container}
234
	str := strings.TrimPrefix(strings.TrimSuffix(string(b), `"`), `"`)
235
	for i, f := range strings.Split(str, "/") {
236
		var err error
237
		switch ft[i] {
238
		case Namespace:
239
			s.Namespaces = parseToIncludeTypeSlice(f)
240
		case Deployment:
241
			s.Deployments = parseToIncludeTypeSlice(f)
242
		case Pod:
243
			s.Pods = parseToIncludeTypeSlice(f)
244
		case Label:
245
			s.Labels, err = parseToIncludeTypeMap(f)
246
			if err != nil {
247
				return err
248
			}
249
		case Annotation:
250
			s.Annotations, err = parseToIncludeTypeMap(f)
251
			if err != nil {
252
				return err
253
			}
254
		case Container:
255
			s.Containers = parseToIncludeTypeSlice(f)
256
		}
257
	}
258

259
	return nil
260
}
261

262
func (s *SelectionSpec) MarshalJSON() ([]byte, error) {
263
	out := fmt.Sprint(strings.Join(s.Namespaces, ","))
264
	out += fmt.Sprintf("/%s", strings.Join(s.Deployments, ","))
265
	out += fmt.Sprintf("/%s", strings.Join(s.Pods, ","))
266
	tmp := []string{}
267
	for k, v := range s.Labels {
268
		tmp = append(tmp, fmt.Sprintf("%s=%s", k, v))
269
	}
270
	out += fmt.Sprintf("/%s", strings.Join(tmp, ","))
271
	tmp = []string{}
272
	for k, v := range s.Annotations {
273
		tmp = append(tmp, fmt.Sprintf("%s=%s", k, v))
274
	}
275
	out += fmt.Sprintf("/%s", strings.Join(tmp, ","))
276
	out += fmt.Sprintf("/%s", strings.Join(s.Containers, ","))
277
	return []byte(`"` + out + `"`), nil
278
}
279

280
type Duration time.Duration
281

282
func (d Duration) MarshalJSON() ([]byte, error) {
283
	return json.Marshal(time.Duration(d).String())
284
}
285

286
func (d *Duration) UnmarshalJSON(b []byte) error {
287
	var v any
288
	if err := json.Unmarshal(b, &v); err != nil {
289
		return err
290
	}
291
	switch value := v.(type) {
292
	case float64:
293
		*d = Duration(time.Duration(value))
294
		return nil
295
	case string:
296
		tmp, err := time.ParseDuration(value)
297
		if err != nil {
298
			return err
299
		}
300
		*d = Duration(tmp)
301
		return nil
302
	default:
303
		return errors.New("invalid duration")
304
	}
305
}
306

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

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

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

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