tetragon

Форк
0
362 строки · 10.7 Кб
1
// SPDX-License-Identifier: Apache-2.0
2
// Copyright Authors of Tetragon
3

4
package common
5

6
import (
7
	"fmt"
8
	"path/filepath"
9
	"strings"
10

11
	"github.com/cilium/tetragon/pkg/logger"
12
	"google.golang.org/protobuf/compiler/protogen"
13
	"google.golang.org/protobuf/reflect/protoreflect"
14
)
15

16
// TetragonPackageName is the import path for the Tetragon package
17
var TetragonPackageName = "github.com/cilium/tetragon"
18

19
// TetragonApiPackageName is the import path for the code generated package
20
var TetragonApiPackageName = "api/v1/tetragon"
21

22
// TetragonCopyrightHeader is the license header to prepend to all generated files
23
var TetragonCopyrightHeader = `// SPDX-License-Identifier: Apache-2.0
24
// Copyright Authors of Tetragon`
25

26
// NewFile creates a new pakage and file in the project
27
func NewFile(gen *protogen.Plugin, file *protogen.File, pkg string, pkgName string, fileName string) *protogen.GeneratedFile {
28
	importPath := filepath.Join(string(file.GoImportPath), pkg)
29
	pathSuffix := filepath.Base(file.GeneratedFilenamePrefix)
30
	fileName = filepath.Join(strings.TrimSuffix(file.GeneratedFilenamePrefix, pathSuffix), pkg, fmt.Sprintf("%s.pb.go", fileName))
31
	logger.GetLogger().Infof("%s", fileName)
32

33
	g := gen.NewGeneratedFile(fileName, protogen.GoImportPath(importPath))
34
	g.P(TetragonCopyrightHeader)
35
	g.P()
36

37
	g.P("// Code generated by protoc-gen-go-tetragon. DO NOT EDIT")
38
	g.P()
39

40
	g.P("package ", pkgName)
41
	g.P()
42

43
	return g
44
}
45

46
// NewCodegenFile creates a new codegen pakage and file in the project
47
func NewCodegenFile(gen *protogen.Plugin, file *protogen.File, pkg string) *protogen.GeneratedFile {
48
	pkgName := filepath.Base(pkg)
49
	pkg = filepath.Join("codegen", pkg)
50

51
	return NewFile(gen, file, pkg, pkgName, pkgName)
52
}
53

54
// GoIdent is a convenience helper that returns a qualified go ident as a string for
55
// a given import package and name
56
func GoIdent(g *protogen.GeneratedFile, importPath string, name string) string {
57
	return g.QualifiedGoIdent(protogen.GoIdent{
58
		GoName:       name,
59
		GoImportPath: protogen.GoImportPath(importPath),
60
	})
61
}
62

63
// TetragonApiIdent is a convenience helper that calls GoIdent with the path to the
64
// Tetragon API package.
65
func TetragonApiIdent(g *protogen.GeneratedFile, name string) string {
66
	return TetragonIdent(g, TetragonApiPackageName, name)
67
}
68

69
// TetragonIdent is a convenience helper that calls GoIdent with the path to the
70
// Tetragon package.
71
func TetragonIdent(g *protogen.GeneratedFile, importPath string, name string) string {
72
	importPath = filepath.Join(TetragonPackageName, importPath)
73
	return GoIdent(g, importPath, name)
74
}
75

76
// GeneratedIdent is a convenience helper that returns a qualified go ident as a string for
77
// a given import package and name within the codegen package
78
func GeneratedIdent(g *protogen.GeneratedFile, importPath string, name string) string {
79
	importPath = filepath.Join(TetragonPackageName, TetragonApiPackageName, "codegen", importPath)
80
	return GoIdent(g, importPath, name)
81
}
82

83
// Logger is a convenience helper that generates a call to logger.GetLogger()
84
func Logger(g *protogen.GeneratedFile) string {
85
	return fmt.Sprintf("%s()", GoIdent(g, "github.com/cilium/tetragon/pkg/logger", "GetLogger"))
86
}
87

88
func ProcessIdent(g *protogen.GeneratedFile) string {
89
	importPath := filepath.Join("github.com/cilium/tetragon/api/v1/tetragon")
90
	return GoIdent(g, importPath, "Process")
91
}
92

93
func ProcessKprobeIdent(g *protogen.GeneratedFile) string {
94
	importPath := filepath.Join("github.com/cilium/tetragon/api/v1/tetragon")
95
	return GoIdent(g, importPath, "ProcessKprobe")
96
}
97

98
func ListMatcherIdent(g *protogen.GeneratedFile, name string) string {
99
	importPath := filepath.Join("github.com/cilium/tetragon/pkg/matchers/listmatcher")
100
	return GoIdent(g, importPath, name)
101
}
102

103
func StringMatcherIdent(g *protogen.GeneratedFile, name string) string {
104
	importPath := filepath.Join("github.com/cilium/tetragon/pkg/matchers/stringmatcher")
105
	return GoIdent(g, importPath, name)
106
}
107

108
func BytesMatcherIdent(g *protogen.GeneratedFile, name string) string {
109
	importPath := filepath.Join("github.com/cilium/tetragon/pkg/matchers/bytesmatcher")
110
	return GoIdent(g, importPath, name)
111
}
112

113
func DurationMatcherIdent(g *protogen.GeneratedFile, name string) string {
114
	importPath := filepath.Join("github.com/cilium/tetragon/pkg/matchers/durationmatcher")
115
	return GoIdent(g, importPath, name)
116
}
117

118
func TimestampMatcherIdent(g *protogen.GeneratedFile, name string) string {
119
	importPath := filepath.Join("github.com/cilium/tetragon/pkg/matchers/timestampmatcher")
120
	return GoIdent(g, importPath, name)
121
}
122

123
func PkgProcessIdent(g *protogen.GeneratedFile, name string) string {
124
	importPath := filepath.Join("github.com/cilium/tetragon/pkg/process")
125
	return GoIdent(g, importPath, name)
126
}
127

128
// FmtErrorf is a convenience helper that generates a call to fmt.Errorf
129
func FmtErrorf(g *protogen.GeneratedFile, fmt_ string, args ...string) string {
130
	args = append([]string{fmt.Sprintf("\"%s\"", fmt_)}, args...)
131
	return fmt.Sprintf("%s(%s)", GoIdent(g, "fmt", "Errorf"), strings.Join(args, ", "))
132
}
133

134
// FmtSprintf is a convenience helper that generates a call to fmt.Sprintf
135
func FmtSprintf(g *protogen.GeneratedFile, fmt_ string, args ...string) string {
136
	args = append([]string{fmt.Sprintf("\"%s\"", fmt_)}, args...)
137
	return fmt.Sprintf("%s(%s)", GoIdent(g, "fmt", "Sprintf"), strings.Join(args, ", "))
138
}
139

140
// EventFieldCheck returns true if the event has the field
141
func EventFieldCheck(msg *protogen.Message, field string) bool {
142
	return msg.Desc.Fields().ByName(protoreflect.Name(field)) != nil
143
}
144

145
// IsProcessEvent returns true if the message is an Tetragon event that has a process field
146
func IsProcessEvent(msg *protogen.Message) bool {
147
	return EventFieldCheck(msg, "process")
148
}
149

150
// IsParentEvent returns true if the message is an Tetragon event that has a parent field
151
func IsParentEvent(msg *protogen.Message) bool {
152
	return EventFieldCheck(msg, "parent")
153
}
154

155
// StructTag is a convenience helper that formats a struct tag
156
func StructTag(tag string) string {
157
	return fmt.Sprintf("`%s`", tag)
158
}
159

160
var eventsCache []*protogen.Message
161

162
type GetEventsResponseOneofInfo struct {
163
	TypeName  string
164
	FieldName string
165
}
166

167
func GetEventsResponseOneofs(files []*protogen.File) ([]GetEventsResponseOneofInfo, error) {
168
	// find the GetEventsResponse type
169
	var getEventsResponse *protogen.Message
170
	for _, f := range files {
171
		for _, msg := range f.Messages {
172
			if msg.GoIdent.GoName == "GetEventsResponse" {
173
				getEventsResponse = msg
174
				break
175
			}
176
		}
177
	}
178
	if getEventsResponse == nil {
179
		return nil, fmt.Errorf("Unable to find GetEventsResponse message")
180
	}
181

182
	var eventOneof *protogen.Oneof
183
	for _, oneof := range getEventsResponse.Oneofs {
184
		if oneof.Desc.Name() == "event" {
185
			eventOneof = oneof
186
			break
187
		}
188
	}
189
	if eventOneof == nil {
190
		return nil, fmt.Errorf("Unable to find GetEventsResponse.event")
191
	}
192

193
	var info []GetEventsResponseOneofInfo
194
	for _, oneof := range eventOneof.Fields {
195
		info = append(info, GetEventsResponseOneofInfo{
196
			TypeName:  strings.TrimPrefix(oneof.GoIdent.GoName, "GetEventsResponse_"),
197
			FieldName: oneof.Desc.TextName(),
198
		})
199
	}
200

201
	return info, nil
202
}
203

204
// GetEvents returns a list of all messages that are events
205
func GetEvents(files []*protogen.File) ([]*protogen.Message, error) {
206
	if len(eventsCache) != 0 {
207
		return eventsCache, nil
208
	}
209

210
	var getEventsResponse *protogen.Message
211
	for _, f := range files {
212
		for _, msg := range f.Messages {
213
			if msg.GoIdent.GoName == "GetEventsResponse" {
214
				getEventsResponse = msg
215
				break
216
			}
217
		}
218
	}
219
	if getEventsResponse == nil {
220
		return nil, fmt.Errorf("Unable to find GetEventsResponse message")
221
	}
222

223
	var eventOneof *protogen.Oneof
224
	for _, oneof := range getEventsResponse.Oneofs {
225
		if oneof.Desc.Name() == "event" {
226
			eventOneof = oneof
227
			break
228
		}
229
	}
230
	if eventOneof == nil {
231
		return nil, fmt.Errorf("Unable to find GetEventsResponse.event")
232
	}
233

234
	validNames := make(map[string]struct{})
235
	for _, type_ := range eventOneof.Fields {
236
		name := strings.TrimPrefix(type_.GoIdent.GoName, "GetEventsResponse_")
237
		validNames[name] = struct{}{}
238
	}
239

240
	for _, f := range files {
241
		for _, msg := range f.Messages {
242
			if _, ok := validNames[string(msg.Desc.Name())]; ok {
243
				eventsCache = append(eventsCache, msg)
244
			}
245
		}
246
	}
247

248
	return eventsCache, nil
249
}
250

251
var fieldsCache []*protogen.Message
252

253
// isReservedField marks message types that we don't want to generate event checkers for
254
var isReservedField = map[string]struct{}{
255
	"Timestamp":   {},
256
	"UInt32Value": {},
257
	"Int32Value":  {},
258
	"UInt64Value": {},
259
	"Int64Value":  {},
260
	"StringValue": {},
261
	"Duration":    {},
262
	"BoolValue":   {},
263
}
264

265
// GetFields returns a list of all messages that are fields
266
func GetFields(files []*protogen.File) ([]*protogen.Message, error) {
267
	if len(fieldsCache) == 0 {
268
		events, err := GetEvents(files)
269
		if err != nil {
270
			return nil, err
271
		}
272

273
		validFields := make(map[string]struct{})
274
		for _, event := range events {
275
			fields := getFieldsForMessage(event)
276
			for _, field := range fields {
277
				if field.Message == nil {
278
					continue
279
				}
280
				if _, reserved := isReservedField[field.Message.GoIdent.GoName]; !reserved {
281
					validFields[field.Message.GoIdent.GoName] = struct{}{}
282
				}
283
			}
284
		}
285

286
		for _, f := range files {
287
			for _, msg := range f.Messages {
288
				if _, ok := validFields[string(msg.Desc.Name())]; ok {
289
					fieldsCache = append(fieldsCache, msg)
290
				}
291
			}
292
		}
293
	}
294

295
	return fieldsCache, nil
296
}
297

298
// getFieldsForMessage recursively looks up all the fields for a given message
299
func getFieldsForMessage(msg *protogen.Message) []*protogen.Field {
300
	seen := make(map[string]struct{})
301
	return __getFieldsForMessage(msg, seen)
302
}
303

304
// __getFieldsForMessage is the underlying recusion logic of getFieldsForMessage
305
func __getFieldsForMessage(msg *protogen.Message, seen map[string]struct{}) []*protogen.Field {
306
	var fields []*protogen.Field
307

308
	for _, field := range msg.Fields {
309
		if field.Message == nil {
310
			continue
311
		}
312
		fieldType := field.Message.GoIdent.GoName
313
		if _, ok := seen[fieldType]; ok {
314
			continue
315
		}
316
		seen[fieldType] = struct{}{}
317
		fields = append(fields, field)
318
		fields = append(fields, __getFieldsForMessage(field.Message, seen)...)
319
	}
320

321
	return fields
322
}
323

324
var enumsCache []*protogen.Enum
325

326
// GetEnums returns a list of all enums that are message fields
327
func GetEnums(files []*protogen.File) ([]*protogen.Enum, error) {
328
	if len(enumsCache) == 0 {
329
		events, err := GetEvents(files)
330
		if err != nil {
331
			return nil, err
332
		}
333

334
		fields, err := GetFields(files)
335
		if err != nil {
336
			return nil, err
337
		}
338

339
		eventsAndFields := append(events, fields...)
340

341
		validNames := make(map[string]struct{})
342
		for _, msg := range eventsAndFields {
343
			for _, field := range msg.Fields {
344
				enum := field.Enum
345
				if enum == nil {
346
					continue
347
				}
348
				validNames[string(enum.Desc.Name())] = struct{}{}
349
			}
350
		}
351

352
		for _, f := range files {
353
			for _, enum := range f.Enums {
354
				if _, ok := validNames[string(enum.Desc.Name())]; ok {
355
					enumsCache = append(enumsCache, enum)
356
				}
357
			}
358
		}
359
	}
360

361
	return enumsCache, nil
362
}
363

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

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

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

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