Skip to content

Commit 3d42ddb

Browse files
Give MySQL sql_log_bin at DSN level to take parameter into account (#171)
Signed-off-by: Florian Gaillot <[email protected]>
1 parent 4988633 commit 3d42ddb

File tree

8 files changed

+42
-59
lines changed

8 files changed

+42
-59
lines changed

pkg/clients/mysql/mysql.go

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"database/sql"
66
"fmt"
7+
"strconv"
78
"strings"
89

910
"github.com/crossplane-contrib/provider-sql/pkg/clients/xsql"
@@ -16,7 +17,6 @@ import (
1617

1718
const (
1819
errNotSupported = "%s not supported by mysql client"
19-
errSetSQLLogBin = "cannot set sql_log_bin = 0"
2020
errFlushPriv = "cannot flush privileges"
2121
)
2222

@@ -28,7 +28,7 @@ type mySQLDB struct {
2828
}
2929

3030
// New returns a new MySQL database client.
31-
func New(creds map[string][]byte, tls *string) xsql.DB {
31+
func New(creds map[string][]byte, tls *string, binlog *bool) xsql.DB {
3232
// TODO(negz): Support alternative connection secret formats?
3333
endpoint := string(creds[xpv1.ResourceCredentialsSecretEndpointKey])
3434
port := string(creds[xpv1.ResourceCredentialsSecretPortKey])
@@ -38,7 +38,11 @@ func New(creds map[string][]byte, tls *string) xsql.DB {
3838
defaultTLS := "preferred"
3939
tls = &defaultTLS
4040
}
41-
dsn := DSN(username, password, endpoint, port, *tls)
41+
if binlog == nil {
42+
defaultBinlog := true
43+
binlog = &defaultBinlog
44+
}
45+
dsn := DSN(username, password, endpoint, port, *tls, *binlog)
4246

4347
return mySQLDB{
4448
dsn: dsn,
@@ -49,16 +53,17 @@ func New(creds map[string][]byte, tls *string) xsql.DB {
4953
}
5054

5155
// DSN returns the DSN URL
52-
func DSN(username, password, endpoint, port, tls string) string {
56+
func DSN(username, password, endpoint, port, tls string, binlog bool) string {
5357
// Use net/url UserPassword to encode the username and password
5458
// This will ensure that any special characters in the username or password
5559
// are percent-encoded for use in the user info portion of the DSN URL
56-
return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s",
60+
return fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s",
5761
username,
5862
password,
5963
endpoint,
6064
port,
61-
tls)
65+
tls,
66+
strconv.FormatBool(binlog))
6267
}
6368

6469
// ExecTx is unsupported in MySQL.
@@ -143,30 +148,16 @@ type ExecQuery struct {
143148

144149
// ExecOptions parametrizes which optional statements will be executed before or after ExecQuery.Query
145150
type ExecOptions struct {
146-
// Binlog defines whether storing binlogs will be disabled before executing the query. Defaults to true
147-
Binlog *bool
148151
// Flush defines whether privileges will be flushed after executing the query. Defaults to true
149152
Flush *bool
150153
}
151154

152-
// ExecWithBinlogAndFlush is a wrapper function for xsql.DB.Exec() that allows the execution of optional queries before and after the provided query
153-
func ExecWithBinlogAndFlush(ctx context.Context, db xsql.DB, query ExecQuery, options ExecOptions) error {
154-
if options.Binlog == nil {
155-
options.Binlog = ptr.To(true)
156-
}
157-
155+
// ExecWithFlush is a wrapper function for xsql.DB.Exec() that allows the execution of optional queries before and after the provided query
156+
func ExecWithFlush(ctx context.Context, db xsql.DB, query ExecQuery, options ExecOptions) error {
158157
if options.Flush == nil {
159158
options.Flush = ptr.To(true)
160159
}
161160

162-
if !*options.Binlog {
163-
if err := db.Exec(ctx, xsql.Query{
164-
String: "SET sql_log_bin = 0",
165-
}); err != nil {
166-
return errors.Wrap(err, errSetSQLLogBin)
167-
}
168-
}
169-
170161
if err := db.Exec(ctx, xsql.Query{
171162
String: query.Query,
172163
}); err != nil {

pkg/clients/mysql/mysql_test.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package mysql
22

33
import (
44
"fmt"
5+
"strconv"
56
"testing"
67
)
78

@@ -11,13 +12,15 @@ func TestDSNURLEscaping(t *testing.T) {
1112
user := "username"
1213
rawPass := "password^"
1314
tls := "true"
14-
dsn := DSN(user, rawPass, endpoint, port, tls)
15-
if dsn != fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s",
15+
binlog := false
16+
dsn := DSN(user, rawPass, endpoint, port, tls, binlog)
17+
if dsn != fmt.Sprintf("%s:%s@tcp(%s:%s)/?tls=%s&sql_log_bin=%s",
1618
user,
1719
rawPass,
1820
endpoint,
1921
port,
20-
tls) {
22+
tls,
23+
strconv.FormatBool(binlog)) {
2124
t.Errorf("DSN string did not match expected output with URL encoded")
2225
}
2326
}

pkg/controller/mysql/database/reconciler.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
7777
type connector struct {
7878
kube client.Client
7979
usage resource.Tracker
80-
newDB func(creds map[string][]byte, tls *string) xsql.DB
80+
newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB
8181
}
8282

8383
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -110,7 +110,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
110110
return nil, errors.Wrap(err, errGetSecret)
111111
}
112112

113-
return &external{db: c.newDB(s.Data, pc.Spec.TLS)}, nil
113+
return &external{db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog)}, nil
114114
}
115115

116116
type external struct{ db xsql.DB }
@@ -148,10 +148,9 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
148148
return managed.ExternalCreation{}, errors.New(errNotDatabase)
149149
}
150150

151-
binlog := cr.Spec.ForProvider.BinLog
152151
query := "CREATE DATABASE " + mysql.QuoteIdentifier(meta.GetExternalName(cr))
153152

154-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateDB}, mysql.ExecOptions{Binlog: binlog, Flush: ptr.To(false)}); err != nil {
153+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateDB}, mysql.ExecOptions{Flush: ptr.To(false)}); err != nil {
155154
return managed.ExternalCreation{}, err
156155
}
157156

@@ -169,10 +168,9 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error {
169168
return errors.New(errNotDatabase)
170169
}
171170

172-
binlog := cr.Spec.ForProvider.BinLog
173171
query := "DROP DATABASE IF EXISTS " + mysql.QuoteIdentifier(meta.GetExternalName(cr))
174172

175-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropDB}, mysql.ExecOptions{Binlog: binlog, Flush: ptr.To(false)}); err != nil {
173+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropDB}, mysql.ExecOptions{Flush: ptr.To(false)}); err != nil {
176174
return err
177175
}
178176

pkg/controller/mysql/database/reconciler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ func TestConnect(t *testing.T) {
6464
type fields struct {
6565
kube client.Client
6666
usage resource.Tracker
67-
newDB func(creds map[string][]byte, tls *string) xsql.DB
67+
newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB
6868
}
6969

7070
type args struct {

pkg/controller/mysql/grant/reconciler.go

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
8787
type connector struct {
8888
kube client.Client
8989
usage resource.Tracker
90-
newDB func(creds map[string][]byte, tls *string) xsql.DB
90+
newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB
9191
}
9292

9393
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -121,7 +121,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
121121
}
122122

123123
return &external{
124-
db: c.newDB(s.Data, pc.Spec.TLS),
124+
db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog),
125125
kube: c.kube,
126126
}, nil
127127
}
@@ -259,10 +259,9 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
259259
table := defaultIdentifier(cr.Spec.ForProvider.Table)
260260

261261
privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice())
262-
binlog := cr.Spec.ForProvider.BinLog
263262
query := createGrantQuery(privileges, dbname, username, table, grantOption)
264263

265-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}, mysql.ExecOptions{Binlog: binlog}); err != nil {
264+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateGrant}, mysql.ExecOptions{}); err != nil {
266265
return managed.ExternalCreation{}, err
267266
}
268267
return managed.ExternalCreation{}, nil
@@ -277,7 +276,6 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
277276
username := *cr.Spec.ForProvider.User
278277
dbname := defaultIdentifier(cr.Spec.ForProvider.Database)
279278
table := defaultIdentifier(cr.Spec.ForProvider.Table)
280-
binlog := cr.Spec.ForProvider.BinLog
281279

282280
observed := cr.Status.AtProvider.Privileges
283281
desired := cr.Spec.ForProvider.Privileges.ToStringSlice()
@@ -287,11 +285,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
287285
sort.Strings(toRevoke)
288286
privileges, grantOption := getPrivilegesString(toRevoke)
289287
query := createRevokeQuery(privileges, dbname, username, table, grantOption)
290-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db,
288+
if err := mysql.ExecWithFlush(ctx, c.db,
291289
mysql.ExecQuery{
292290
Query: query, ErrorValue: errRevokeGrant,
293-
}, mysql.ExecOptions{
294-
Binlog: binlog}); err != nil {
291+
}, mysql.ExecOptions{}); err != nil {
295292
return managed.ExternalUpdate{}, err
296293
}
297294
}
@@ -300,11 +297,10 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
300297
sort.Strings(toGrant)
301298
privileges, grantOption := getPrivilegesString(toGrant)
302299
query := createGrantQuery(privileges, dbname, username, table, grantOption)
303-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db,
300+
if err := mysql.ExecWithFlush(ctx, c.db,
304301
mysql.ExecQuery{
305302
Query: query, ErrorValue: errCreateGrant,
306-
}, mysql.ExecOptions{
307-
Binlog: binlog}); err != nil {
303+
}, mysql.ExecOptions{}); err != nil {
308304
return managed.ExternalUpdate{}, err
309305
}
310306
}
@@ -369,12 +365,11 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error {
369365
username := *cr.Spec.ForProvider.User
370366
dbname := defaultIdentifier(cr.Spec.ForProvider.Database)
371367
table := defaultIdentifier(cr.Spec.ForProvider.Table)
372-
binlog := cr.Spec.ForProvider.BinLog
373368

374369
privileges, grantOption := getPrivilegesString(cr.Spec.ForProvider.Privileges.ToStringSlice())
375370
query := createRevokeQuery(privileges, dbname, username, table, grantOption)
376371

377-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}, mysql.ExecOptions{Binlog: binlog}); err != nil {
372+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errRevokeGrant}, mysql.ExecOptions{}); err != nil {
378373
var myErr *mysqldriver.MySQLError
379374
if errors.As(err, &myErr) && myErr.Number == errCodeNoSuchGrant {
380375
// MySQL automatically deletes related grants if the user has been deleted

pkg/controller/mysql/grant/reconciler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ func TestConnect(t *testing.T) {
7474
type fields struct {
7575
kube client.Client
7676
usage resource.Tracker
77-
newDB func(creds map[string][]byte, tls *string) xsql.DB
77+
newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB
7878
}
7979

8080
type args struct {

pkg/controller/mysql/user/reconciler.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func Setup(mgr ctrl.Manager, o xpcontroller.Options) error {
8282
type connector struct {
8383
kube client.Client
8484
usage resource.Tracker
85-
newDB func(creds map[string][]byte, tls *string) xsql.DB
85+
newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB
8686
}
8787

8888
func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.ExternalClient, error) {
@@ -116,7 +116,7 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
116116
}
117117

118118
return &external{
119-
db: c.newDB(s.Data, pc.Spec.TLS),
119+
db: c.newDB(s.Data, pc.Spec.TLS, cr.Spec.ForProvider.BinLog),
120120
kube: c.kube,
121121
}, nil
122122
}
@@ -251,8 +251,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
251251
}
252252

253253
ro := resourceOptionsToClauses(cr.Spec.ForProvider.ResourceOptions)
254-
binlog := cr.Spec.ForProvider.BinLog
255-
if err := c.executeCreateUserQuery(ctx, username, host, ro, pw, binlog); err != nil {
254+
if err := c.executeCreateUserQuery(ctx, username, host, ro, pw); err != nil {
256255
return managed.ExternalCreation{}, err
257256
}
258257

@@ -265,7 +264,7 @@ func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.Ext
265264
}, nil
266265
}
267266

268-
func (c *external) executeCreateUserQuery(ctx context.Context, username string, host string, resourceOptionsClauses []string, pw string, binlog *bool) error {
267+
func (c *external) executeCreateUserQuery(ctx context.Context, username string, host string, resourceOptionsClauses []string, pw string) error {
269268
resourceOptions := ""
270269
if len(resourceOptionsClauses) != 0 {
271270
resourceOptions = fmt.Sprintf(" WITH %s", strings.Join(resourceOptionsClauses, " "))
@@ -279,7 +278,7 @@ func (c *external) executeCreateUserQuery(ctx context.Context, username string,
279278
resourceOptions,
280279
)
281280

282-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil {
281+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errCreateUser}, mysql.ExecOptions{}); err != nil {
283282
return err
284283
}
285284

@@ -303,14 +302,13 @@ func (c *external) Update(ctx context.Context, mg resource.Managed) (managed.Ext
303302
if len(rochanged) > 0 {
304303
resourceOptions := fmt.Sprintf("WITH %s", strings.Join(ro, " "))
305304

306-
binlog := cr.Spec.ForProvider.BinLog
307305
query := fmt.Sprintf(
308306
"ALTER USER %s@%s %s",
309307
mysql.QuoteValue(username),
310308
mysql.QuoteValue(host),
311309
resourceOptions,
312310
)
313-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil {
311+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{}); err != nil {
314312
return managed.ExternalUpdate{}, err
315313
}
316314

@@ -336,9 +334,8 @@ func (c *external) UpdatePassword(ctx context.Context, cr *v1alpha1.User, userna
336334
}
337335

338336
if pwchanged {
339-
binlog := cr.Spec.ForProvider.BinLog
340337
query := fmt.Sprintf("ALTER USER %s@%s IDENTIFIED BY %s", mysql.QuoteValue(username), mysql.QuoteValue(host), mysql.QuoteValue(pw))
341-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{Binlog: binlog}); err != nil {
338+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errUpdateUser}, mysql.ExecOptions{}); err != nil {
342339
return managed.ConnectionDetails{}, err
343340
}
344341

@@ -358,9 +355,8 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error {
358355

359356
username, host := mysql.SplitUserHost(meta.GetExternalName(cr))
360357

361-
binlog := cr.Spec.ForProvider.BinLog
362358
query := fmt.Sprintf("DROP USER IF EXISTS %s@%s", mysql.QuoteValue(username), mysql.QuoteValue(host))
363-
if err := mysql.ExecWithBinlogAndFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropUser}, mysql.ExecOptions{Binlog: binlog}); err != nil {
359+
if err := mysql.ExecWithFlush(ctx, c.db, mysql.ExecQuery{Query: query, ErrorValue: errDropUser}, mysql.ExecOptions{}); err != nil {
364360
return err
365361
}
366362

pkg/controller/mysql/user/reconciler_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ func TestConnect(t *testing.T) {
7272
type fields struct {
7373
kube client.Client
7474
usage resource.Tracker
75-
newDB func(creds map[string][]byte, tls *string) xsql.DB
75+
newDB func(creds map[string][]byte, tls *string, binlog *bool) xsql.DB
7676
}
7777

7878
type args struct {

0 commit comments

Comments
 (0)