Skip to content

Commit 0896d15

Browse files
lysuzz-jason
authored andcommitted
plugin: add audit plugin extension point (#9136) (#9954)
1 parent 1dba727 commit 0896d15

File tree

22 files changed

+541
-71
lines changed

22 files changed

+541
-71
lines changed

cmd/pluginpkg/pluginpkg.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,18 @@ func PluginManifest() *plugin.Manifest {
6262
},
6363
{{end}}
6464
},
65-
Validate: {{.validate}},
66-
OnInit: {{.onInit}},
67-
OnShutdown: {{.onShutdown}},
65+
{{if .validate }}
66+
Validate: {{.validate}},
67+
{{end}}
68+
{{if .onInit }}
69+
OnInit: {{.onInit}},
70+
{{end}}
71+
{{if .onShutdown }}
72+
OnShutdown: {{.onShutdown}},
73+
{{end}}
74+
{{if .onFlush }}
75+
OnFlush: {{.onFlush}},
76+
{{end}}
6877
},
6978
{{range .export}}
7079
{{.extPoint}}: {{.impl}},

executor/adapter.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,14 @@ import (
3232
"github.com/pingcap/tidb/kv"
3333
"github.com/pingcap/tidb/metrics"
3434
plannercore "github.com/pingcap/tidb/planner/core"
35+
"github.com/pingcap/tidb/plugin"
3536
"github.com/pingcap/tidb/sessionctx"
3637
"github.com/pingcap/tidb/sessionctx/variable"
3738
"github.com/pingcap/tidb/util/chunk"
3839
"github.com/pingcap/tidb/util/logutil"
3940
"github.com/pingcap/tidb/util/sqlexec"
4041
log "github.com/sirupsen/logrus"
42+
"go.uber.org/zap"
4143
"golang.org/x/net/context"
4244
)
4345

@@ -124,6 +126,7 @@ func (a *recordSet) Close() error {
124126
if a.processinfo != nil {
125127
a.processinfo.SetProcessInfo("")
126128
}
129+
a.stmt.logAudit()
127130
return errors.Trace(err)
128131
}
129132

@@ -286,6 +289,7 @@ func (a *ExecStmt) handleNoDelayExecutor(ctx context.Context, sctx sessionctx.Co
286289
}
287290
}
288291
a.LogSlowQuery(txnTS, err == nil)
292+
a.logAudit()
289293
}()
290294

291295
err = e.Next(ctx, e.newFirstChunk())
@@ -349,6 +353,24 @@ func (a *ExecStmt) buildExecutor(ctx sessionctx.Context) (Executor, error) {
349353
// QueryReplacer replaces new line and tab for grep result including query string.
350354
var QueryReplacer = strings.NewReplacer("\r", " ", "\n", " ", "\t", " ")
351355

356+
func (a *ExecStmt) logAudit() {
357+
sessVars := a.Ctx.GetSessionVars()
358+
if sessVars.InRestrictedSQL {
359+
return
360+
}
361+
err := plugin.ForeachPlugin(plugin.Audit, func(p *plugin.Plugin) error {
362+
audit := plugin.DeclareAuditManifest(p.Manifest)
363+
if audit.OnGeneralEvent != nil {
364+
cmd := mysql.Command2Str[byte(atomic.LoadUint32(&a.Ctx.GetSessionVars().CommandValue))]
365+
audit.OnGeneralEvent(context.Background(), sessVars, plugin.Log, cmd)
366+
}
367+
return nil
368+
})
369+
if err != nil {
370+
logutil.Logger(context.Background()).Error("log audit log failure", zap.Error(err))
371+
}
372+
}
373+
352374
// LogSlowQuery is used to print the slow query in the log files.
353375
func (a *ExecStmt) LogSlowQuery(txnTS uint64, succ bool) {
354376
level := log.GetLevel()

executor/set.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/pingcap/parser/terror"
2525
"github.com/pingcap/tidb/domain"
2626
"github.com/pingcap/tidb/expression"
27+
"github.com/pingcap/tidb/plugin"
2728
"github.com/pingcap/tidb/sessionctx"
2829
"github.com/pingcap/tidb/sessionctx/variable"
2930
"github.com/pingcap/tidb/types"
@@ -139,6 +140,16 @@ func (e *SetExecutor) setSysVariable(name string, v *expression.VarAssignment) e
139140
if err != nil {
140141
return errors.Trace(err)
141142
}
143+
err = plugin.ForeachPlugin(plugin.Audit, func(p *plugin.Plugin) error {
144+
auditPlugin := plugin.DeclareAuditManifest(p.Manifest)
145+
if auditPlugin.OnGlobalVariableEvent != nil {
146+
auditPlugin.OnGlobalVariableEvent(context.Background(), e.ctx.GetSessionVars(), name, svalue)
147+
}
148+
return nil
149+
})
150+
if err != nil {
151+
return err
152+
}
142153
} else {
143154
// Set session scope system variable.
144155
if sysVar.Scope&variable.ScopeSession == 0 {

planner/core/optimizer.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ func Optimize(ctx sessionctx.Context, node ast.Node, is infoschema.InfoSchema) (
7676
return nil, errors.Trace(err)
7777
}
7878

79+
ctx.GetSessionVars().StmtCtx.Tables = builder.GetDBTableInfo()
80+
7981
// Maybe it's better to move this to Preprocess, but check privilege need table
8082
// information, which is collected into visitInfo during logical plan builder.
8183
if pm := privilege.GetPrivilegeManager(ctx); pm != nil {

planner/core/planbuilder.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/pingcap/tidb/infoschema"
3131
"github.com/pingcap/tidb/planner/property"
3232
"github.com/pingcap/tidb/sessionctx"
33+
"github.com/pingcap/tidb/sessionctx/stmtctx"
3334
"github.com/pingcap/tidb/table"
3435
"github.com/pingcap/tidb/types"
3536
"github.com/pingcap/tidb/types/parser_driver"
@@ -324,6 +325,26 @@ func (b *planBuilder) detectSelectAgg(sel *ast.SelectStmt) bool {
324325
return false
325326
}
326327

328+
// GetDBTableInfo gets the accessed dbs and tables info.
329+
func (b *planBuilder) GetDBTableInfo() []stmtctx.TableEntry {
330+
var tables []stmtctx.TableEntry
331+
existsFunc := func(tbls []stmtctx.TableEntry, tbl *stmtctx.TableEntry) bool {
332+
for _, t := range tbls {
333+
if t == *tbl {
334+
return true
335+
}
336+
}
337+
return false
338+
}
339+
for _, v := range b.visitInfo {
340+
tbl := &stmtctx.TableEntry{DB: v.db, Table: v.table}
341+
if !existsFunc(tables, tbl) {
342+
tables = append(tables, *tbl)
343+
}
344+
}
345+
return tables
346+
}
347+
327348
func getPathByIndexName(paths []*accessPath, idxName model.CIStr, tblInfo *model.TableInfo) *accessPath {
328349
var tablePath *accessPath
329350
for _, path := range paths {

plugin/audit.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright 2019 PingCAP, Inc.
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+
// See the License for the specific language governing permissions and
12+
// limitations under the License.
13+
14+
package plugin
15+
16+
import (
17+
"context"
18+
19+
"github.com/pingcap/parser/auth"
20+
"github.com/pingcap/tidb/sessionctx/variable"
21+
)
22+
23+
// GeneralEvent presents TiDB generate event.
24+
type GeneralEvent byte
25+
26+
const (
27+
// Log presents log event.
28+
Log GeneralEvent = iota
29+
// Error presents error event.
30+
Error
31+
// Result presents result event.
32+
Result
33+
// Status presents status event.
34+
Status
35+
)
36+
37+
// ConnectionEvent presents TiDB connection event.
38+
type ConnectionEvent byte
39+
40+
const (
41+
// Connected presents new connection establish event(finish auth).
42+
Connected ConnectionEvent = iota
43+
// Disconnect presents disconnect event.
44+
Disconnect
45+
// ChangeUser presents change user.
46+
ChangeUser
47+
// PreAuth presents event before start auth.
48+
PreAuth
49+
)
50+
51+
func (c ConnectionEvent) String() string {
52+
switch c {
53+
case Connected:
54+
return "Connected"
55+
case Disconnect:
56+
return "Disconnect"
57+
case ChangeUser:
58+
return "ChangeUser"
59+
case PreAuth:
60+
return "PreAuth"
61+
}
62+
return ""
63+
}
64+
65+
// ParseEvent presents events happen around parser.
66+
type ParseEvent byte
67+
68+
const (
69+
// PreParse presents event before parse.
70+
PreParse ParseEvent = 1 + iota
71+
// PostParse presents event after parse.
72+
PostParse
73+
)
74+
75+
// AuditManifest presents a sub-manifest that every audit plugin must provide.
76+
type AuditManifest struct {
77+
Manifest
78+
// OnConnectionEvent will be called when TiDB receive or disconnect from client.
79+
// return error will ignore and close current connection.
80+
OnConnectionEvent func(ctx context.Context, identity *auth.UserIdentity, event ConnectionEvent, info *variable.ConnectionInfo) error
81+
// OnGeneralEvent will be called during TiDB execution.
82+
OnGeneralEvent func(ctx context.Context, sctx *variable.SessionVars, event GeneralEvent, cmd string)
83+
// OnGlobalVariableEvent will be called when Change GlobalVariable.
84+
OnGlobalVariableEvent func(ctx context.Context, sctx *variable.SessionVars, varName, varValue string)
85+
// OnParseEvent will be called around parse logic.
86+
OnParseEvent func(ctx context.Context, sctx *variable.SessionVars, event ParseEvent) error
87+
}

plugin/conn_ip_example/conn_ip_example.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ func OnShutdown(ctx context.Context, manifest *plugin.Manifest) error {
4040
return nil
4141
}
4242

43-
// NotifyEvent implements TiDB Audit plugin's NotifyEvent SPI.
44-
func NotifyEvent(ctx context.Context) error {
43+
// OnGeneralEvent implements TiDB Audit plugin's OnGeneralEvent SPI.
44+
func OnGeneralEvent(ctx context.Context, sctx *variable.SessionVars, event plugin.GeneralEvent, cmd byte, stmt string) error {
4545
fmt.Println("conn_ip_example notifiy called")
4646
fmt.Println("variable test: ", variable.GetSysVar("conn_ip_example_test_variable").Value)
4747
fmt.Printf("new connection by %s\n", ctx.Value("ip"))

plugin/conn_ip_example/conn_ip_example_test.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,23 @@ func Example_LoadRunShutdownPlugin() {
3030
PluginVarNames: &pluginVarNames,
3131
}
3232

33-
err := plugin.Init(ctx, cfg)
33+
err := plugin.Load(ctx, cfg)
3434
if err != nil {
3535
panic(err)
3636
}
3737

38-
ps := plugin.GetByKind(plugin.Audit)
39-
for _, auditPlugin := range ps {
40-
if auditPlugin.State != plugin.Ready {
41-
continue
42-
}
43-
plugin.DeclareAuditManifest(auditPlugin.Manifest).NotifyEvent(context.Background(), nil)
38+
// load and start TiDB domain.
39+
err = plugin.Init(ctx, cfg)
40+
if err != nil {
41+
panic(err)
42+
}
43+
44+
err = plugin.ForeachPlugin(plugin.Audit, func(auditPlugin *plugin.Plugin) error {
45+
plugin.DeclareAuditManifest(auditPlugin.Manifest).OnGeneralEvent(context.Background(), nil, plugin.Log, "QUERY")
46+
return nil
47+
})
48+
if err != nil {
49+
panic(err)
4450
}
4551

4652
plugin.Shutdown(context.Background())

plugin/conn_ip_example/manifest.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,5 @@ validate = "Validate"
1111
onInit = "OnInit"
1212
onShutdown = "OnShutdown"
1313
export = [
14-
{extPoint="NotifyEvent", impl="NotifyEvent"}
14+
{extPoint="OnGeneralEvent", impl="OnGeneralEvent"}
1515
]

0 commit comments

Comments
 (0)