Skip to content

Commit 7ae32f7

Browse files
author
Shlomi Noach
authored
Merge branch 'master' into skip-strict-mode
2 parents 7d5749b + 2c0aa36 commit 7ae32f7

File tree

6 files changed

+78
-20
lines changed

6 files changed

+78
-20
lines changed

doc/command-line-flags.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,14 @@ While the ongoing estimated number of rows is still heuristic, it's almost exact
111111

112112
Without this parameter, migration is a _noop_: testing table creation and validity of migration, but not touching data.
113113

114+
### force-named-cut-over
115+
116+
If given, a `cut-over` command must name the migrated table, or else ignored.
117+
118+
### force-named-panic
119+
120+
If given, a `panic` command must name the migrated table, or else ignored.
121+
114122
### force-table-names
115123

116124
Table name prefix to be used on the temporary tables.
@@ -193,6 +201,14 @@ Allows `gh-ost` to connect to the MySQL servers using encrypted connections, but
193201

194202
`--ssl-ca=/path/to/ca-cert.pem`: ca certificate file (in PEM format) to use for server certificate verification. If specified, the default system ca cert pool will not be used for verification, only the ca cert provided here. Requires `--ssl`.
195203

204+
### ssl-cert
205+
206+
`--ssl-cert=/path/to/ssl-cert.crt`: SSL public key certificate file (in PEM format).
207+
208+
### ssl-key
209+
210+
`--ssl-key=/path/to/ssl-key.key`: SSL private key file (in PEM format).
211+
196212
### test-on-replica
197213

198214
Issue the migration on a replica; do not modify data on master. Useful for validating, testing and benchmarking. See [`testing-on-replica`](testing-on-replica.md)

go/base/context.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ type MigrationContext struct {
103103
UseTLS bool
104104
TLSAllowInsecure bool
105105
TLSCACertificate string
106+
TLSCertificate string
107+
TLSKey string
106108
CliMasterUser string
107109
CliMasterPassword string
108110

@@ -127,6 +129,7 @@ type MigrationContext struct {
127129
CutOverExponentialBackoff bool
128130
ExponentialBackoffMaxInterval int64
129131
ForceNamedCutOverCommand bool
132+
ForceNamedPanicCommand bool
130133
PanicFlagFile string
131134
HooksPath string
132135
HooksHintMessage string
@@ -703,7 +706,7 @@ func (this *MigrationContext) ApplyCredentials() {
703706

704707
func (this *MigrationContext) SetupTLS() error {
705708
if this.UseTLS {
706-
return this.InspectorConnectionConfig.UseTLS(this.TLSCACertificate, this.TLSAllowInsecure)
709+
return this.InspectorConnectionConfig.UseTLS(this.TLSCACertificate, this.TLSCertificate, this.TLSKey, this.TLSAllowInsecure)
707710
}
708711
return nil
709712
}

go/cmd/gh-ost/main.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ func main() {
5757

5858
flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL hosts")
5959
flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections to MySQL hosts. Requires --ssl")
60+
flag.StringVar(&migrationContext.TLSCertificate, "ssl-cert", "", "Certificate in PEM format for TLS connections to MySQL hosts. Requires --ssl")
61+
flag.StringVar(&migrationContext.TLSKey, "ssl-key", "", "Key in PEM format for TLS connections to MySQL hosts. Requires --ssl")
6062
flag.BoolVar(&migrationContext.TLSAllowInsecure, "ssl-allow-insecure", false, "Skips verification of MySQL hosts' certificate chain and host name. Requires --ssl")
6163

6264
flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)")
@@ -87,6 +89,7 @@ func main() {
8789
flag.BoolVar(&migrationContext.TimestampOldTable, "timestamp-old-table", false, "Use a timestamp in old table name. This makes old table names unique and non conflicting cross migrations")
8890
cutOver := flag.String("cut-over", "atomic", "choose cut-over type (default|atomic, two-step)")
8991
flag.BoolVar(&migrationContext.ForceNamedCutOverCommand, "force-named-cut-over", false, "When true, the 'unpostpone|cut-over' interactive command must name the migrated table")
92+
flag.BoolVar(&migrationContext.ForceNamedPanicCommand, "force-named-panic", false, "When true, the 'panic' interactive command must name the migrated table")
9093

9194
flag.BoolVar(&migrationContext.SwitchToRowBinlogFormat, "switch-to-rbr", false, "let this tool automatically switch binary log format to 'ROW' on the replica, if needed. The format will NOT be switched back. I'm too scared to do that, and wish to protect you if you happen to execute another migration while this one is running")
9295
flag.BoolVar(&migrationContext.AssumeRBR, "assume-rbr", false, "set to 'true' when you know for certain your server uses 'ROW' binlog_format. gh-ost is unable to tell, event after reading binlog_format, whether the replication process does indeed use 'ROW', and restarts replication to be certain RBR setting is applied. Such operation requires SUPER privileges which you might not have. Setting this flag avoids restarting replication and you can proceed to use gh-ost without SUPER privileges")
@@ -205,6 +208,12 @@ func main() {
205208
if migrationContext.TLSCACertificate != "" && !migrationContext.UseTLS {
206209
log.Fatalf("--ssl-ca requires --ssl")
207210
}
211+
if migrationContext.TLSCertificate != "" && !migrationContext.UseTLS {
212+
log.Fatalf("--ssl-cert requires --ssl")
213+
}
214+
if migrationContext.TLSKey != "" && !migrationContext.UseTLS {
215+
log.Fatalf("--ssl-key requires --ssl")
216+
}
208217
if migrationContext.TLSAllowInsecure && !migrationContext.UseTLS {
209218
log.Fatalf("--ssl-allow-insecure requires --ssl")
210219
}

go/logic/server.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,12 +292,22 @@ help # This message
292292
}
293293
case "throttle", "pause", "suspend":
294294
{
295+
if arg != "" && arg != this.migrationContext.OriginalTableName {
296+
// User explicitly provided table name. This is a courtesy protection mechanism
297+
err := fmt.Errorf("User commanded 'throttle' on %s, but migrated table is %s; ignoring request.", arg, this.migrationContext.OriginalTableName)
298+
return NoPrintStatusRule, err
299+
}
295300
atomic.StoreInt64(&this.migrationContext.ThrottleCommandedByUser, 1)
296301
fmt.Fprintf(writer, throttleHint)
297302
return ForcePrintStatusAndHintRule, nil
298303
}
299304
case "no-throttle", "unthrottle", "resume", "continue":
300305
{
306+
if arg != "" && arg != this.migrationContext.OriginalTableName {
307+
// User explicitly provided table name. This is a courtesy protection mechanism
308+
err := fmt.Errorf("User commanded 'no-throttle' on %s, but migrated table is %s; ignoring request.", arg, this.migrationContext.OriginalTableName)
309+
return NoPrintStatusRule, err
310+
}
301311
atomic.StoreInt64(&this.migrationContext.ThrottleCommandedByUser, 0)
302312
return ForcePrintStatusAndHintRule, nil
303313
}
@@ -322,6 +332,15 @@ help # This message
322332
}
323333
case "panic":
324334
{
335+
if arg == "" && this.migrationContext.ForceNamedPanicCommand {
336+
err := fmt.Errorf("User commanded 'panic' without specifying table name, but --force-named-panic is set")
337+
return NoPrintStatusRule, err
338+
}
339+
if arg != "" && arg != this.migrationContext.OriginalTableName {
340+
// User explicitly provided table name. This is a courtesy protection mechanism
341+
err := fmt.Errorf("User commanded 'panic' on %s, but migrated table is %s; ignoring request.", arg, this.migrationContext.OriginalTableName)
342+
return NoPrintStatusRule, err
343+
}
325344
err := fmt.Errorf("User commanded 'panic'. I will now panic, without cleanup. PANIC!")
326345
this.migrationContext.PanicAbort <- err
327346
return NoPrintStatusRule, err

go/mysql/connection.go

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ import (
1616
"github.com/go-sql-driver/mysql"
1717
)
1818

19+
const (
20+
TLS_CONFIG_KEY = "ghost"
21+
)
22+
1923
// ConnectionConfig is the minimal configuration required to connect to a MySQL server
2024
type ConnectionConfig struct {
2125
Key InstanceKey
@@ -57,34 +61,41 @@ func (this *ConnectionConfig) Equals(other *ConnectionConfig) bool {
5761
return this.Key.Equals(&other.Key) || this.ImpliedKey.Equals(other.ImpliedKey)
5862
}
5963

60-
func (this *ConnectionConfig) UseTLS(caCertificatePath string, allowInsecure bool) error {
64+
func (this *ConnectionConfig) UseTLS(caCertificatePath, clientCertificate, clientKey string, allowInsecure bool) error {
6165
var rootCertPool *x509.CertPool
66+
var certs []tls.Certificate
6267
var err error
6368

64-
if !allowInsecure {
65-
if caCertificatePath == "" {
66-
rootCertPool, err = x509.SystemCertPool()
67-
if err != nil {
68-
return err
69-
}
70-
} else {
71-
rootCertPool = x509.NewCertPool()
72-
pem, err := ioutil.ReadFile(caCertificatePath)
73-
if err != nil {
74-
return err
75-
}
76-
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
77-
return errors.New("could not add ca certificate to cert pool")
78-
}
69+
if caCertificatePath == "" {
70+
rootCertPool, err = x509.SystemCertPool()
71+
if err != nil {
72+
return err
73+
}
74+
} else {
75+
rootCertPool = x509.NewCertPool()
76+
pem, err := ioutil.ReadFile(caCertificatePath)
77+
if err != nil {
78+
return err
79+
}
80+
if ok := rootCertPool.AppendCertsFromPEM(pem); !ok {
81+
return errors.New("could not add ca certificate to cert pool")
82+
}
83+
}
84+
if clientCertificate != "" || clientKey != "" {
85+
cert, err := tls.LoadX509KeyPair(clientCertificate, clientKey)
86+
if err != nil {
87+
return err
7988
}
89+
certs = []tls.Certificate{cert}
8090
}
8191

8292
this.tlsConfig = &tls.Config{
93+
Certificates: certs,
8394
RootCAs: rootCertPool,
8495
InsecureSkipVerify: allowInsecure,
8596
}
8697

87-
return mysql.RegisterTLSConfig(this.Key.StringCode(), this.tlsConfig)
98+
return mysql.RegisterTLSConfig(TLS_CONFIG_KEY, this.tlsConfig)
8899
}
89100

90101
func (this *ConnectionConfig) TLSConfig() *tls.Config {
@@ -103,7 +114,7 @@ func (this *ConnectionConfig) GetDBUri(databaseName string) string {
103114
// simplify construction of the DSN below.
104115
tlsOption := "false"
105116
if this.tlsConfig != nil {
106-
tlsOption = this.Key.StringCode()
117+
tlsOption = TLS_CONFIG_KEY
107118
}
108119
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?interpolateParams=%t&autocommit=true&charset=utf8mb4,utf8,latin1&tls=%s", this.User, this.Password, hostname, this.Key.Port, databaseName, interpolateParams, tlsOption)
109120
}

go/mysql/connection_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,5 @@ func TestGetDBUriWithTLSSetup(t *testing.T) {
8080
c.tlsConfig = &tls.Config{}
8181

8282
uri := c.GetDBUri("test")
83-
test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1&tls=myhost:3306")
83+
test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1&tls=ghost")
8484
}

0 commit comments

Comments
 (0)