Skip to content

Commit ff17d2f

Browse files
author
Shlomi Noach
authored
Merge branch 'master' into named-panic
2 parents 6c5805d + a8fae98 commit ff17d2f

File tree

20 files changed

+148
-33
lines changed

20 files changed

+148
-33
lines changed

RELEASE_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.47
1+
1.0.48

build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ function build {
4242
builddir=$(setuptree)
4343
cp $buildpath/$target $builddir/gh-ost/usr/bin
4444
cd $buildpath
45-
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m shlomi-noach --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t rpm .
46-
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m shlomi-noach --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t deb --deb-no-default-config-files .
45+
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m 'shlomi-noach <[email protected]>' --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t rpm .
46+
fpm -v "${RELEASE_VERSION}" --epoch 1 -f -s dir -n gh-ost -m 'shlomi-noach <[email protected]>' --description "GitHub's Online Schema Migrations for MySQL " --url "https://github.com/github/gh-ost" --vendor "GitHub" --license "Apache 2.0" -C $builddir/gh-ost --prefix=/ -t deb --deb-no-default-config-files .
4747
fi
4848
}
4949

doc/command-line-flags.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,18 @@ By default `gh-ost` verifies no foreign keys exist on the migrated table. On ser
185185

186186
See [`approve-renamed-columns`](#approve-renamed-columns)
187187

188+
### ssl
189+
190+
By default `gh-ost` does not use ssl/tls connections to the database servers when performing migrations. This flag instructs `gh-ost` to use encrypted connections. If enabled, `gh-ost` will use the system's ca certificate pool for server certificate verification. If a different certificate is needed for server verification, see `--ssl-ca`. If you wish to skip server verification, but still use encrypted connections, use with `--ssl-allow-insecure`.
191+
192+
### ssl-allow-insecure
193+
194+
Allows `gh-ost` to connect to the MySQL servers using encrypted connections, but without verifying the validity of the certificate provided by the server during the connection. Requires `--ssl`.
195+
196+
### ssl-ca
197+
198+
`--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`.
199+
188200
### test-on-replica
189201

190202
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)

doc/hooks.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ The following variables are available on all hooks:
6969
- `GH_OST_INSPECTED_HOST`
7070
- `GH_OST_EXECUTING_HOST`
7171
- `GH_OST_HOOKS_HINT` - copy of `--hooks-hint` value
72+
- `GH_OST_HOOKS_HINT_OWNER` - copy of `--hooks-hint-owner` value
73+
- `GH_OST_HOOKS_HINT_TOKEN` - copy of `--hooks-hint-token` value
7274
- `GH_OST_DRY_RUN` - whether or not the `gh-ost` run is a dry run
7375

7476
The following variable are available on particular hooks:

doc/questions.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,9 @@ It is therefore unlikely that `gh-ost` will support this behavior.
2828
Yes. TL;DR if running all on same replica/master, make sure to provide `--replica-server-id`. [Read more](cheatsheet.md#concurrent-migrations)
2929

3030
# Why
31+
32+
### Why Is the "Connect to Replica" mode preferred?
33+
34+
To avoid placing extra load on the master. `gh-ost` connects as a replication client. Each additional replica adds some load to the master.
35+
36+
To monitor replication lag from a replica. This makes the replication lag throttle, `--max-lag-millis`, more representative of the lag experienced by other replicas following the master (perhaps N levels deep in a tree of replicas).

go/base/context.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ type MigrationContext struct {
9999
ConfigFile string
100100
CliUser string
101101
CliPassword string
102+
UseTLS bool
103+
TLSAllowInsecure bool
104+
TLSCACertificate string
102105
CliMasterUser string
103106
CliMasterPassword string
104107

@@ -127,6 +130,8 @@ type MigrationContext struct {
127130
PanicFlagFile string
128131
HooksPath string
129132
HooksHintMessage string
133+
HooksHintOwner string
134+
HooksHintToken string
130135

131136
DropServeSocket bool
132137
ServeSocketFile string
@@ -696,6 +701,13 @@ func (this *MigrationContext) ApplyCredentials() {
696701
}
697702
}
698703

704+
func (this *MigrationContext) SetupTLS() error {
705+
if this.UseTLS {
706+
return this.InspectorConnectionConfig.UseTLS(this.TLSCACertificate, this.TLSAllowInsecure)
707+
}
708+
return nil
709+
}
710+
699711
// ReadConfigFile attempts to read the config file, if it exists
700712
func (this *MigrationContext) ReadConfigFile() error {
701713
this.configMutex.Lock()

go/binlog/binlog_entry.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ func NewBinlogEntry(logFile string, logPos uint64) *BinlogEntry {
2626
return binlogEntry
2727
}
2828

29-
// NewBinlogEntry creates an empty, ready to go BinlogEntry object
29+
// NewBinlogEntryAt creates an empty, ready to go BinlogEntry object
3030
func NewBinlogEntryAt(coordinates mysql.BinlogCoordinates) *BinlogEntry {
3131
binlogEntry := &BinlogEntry{
3232
Coordinates: coordinates,
@@ -41,7 +41,7 @@ func (this *BinlogEntry) Duplicate() *BinlogEntry {
4141
return binlogEntry
4242
}
4343

44-
// Duplicate creates and returns a new binlog entry, with some of the attributes pre-assigned
44+
// String() returns a string representation of this binlog entry
4545
func (this *BinlogEntry) String() string {
4646
return fmt.Sprintf("[BinlogEntry at %+v; dml:%+v]", this.Coordinates, this.DmlEvent)
4747
}

go/binlog/gomysql_reader.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ func NewGoMySQLReader(migrationContext *base.MigrationContext) (binlogReader *Go
4646
Port: uint16(binlogReader.connectionConfig.Key.Port),
4747
User: binlogReader.connectionConfig.User,
4848
Password: binlogReader.connectionConfig.Password,
49+
TLSConfig: binlogReader.connectionConfig.TLSConfig(),
4950
UseDecimal: true,
5051
}
5152
binlogReader.binlogSyncer = replication.NewBinlogSyncer(binlogSyncerConfig)
@@ -112,7 +113,7 @@ func (this *GoMySQLReader) handleRowsEvent(ev *replication.BinlogEvent, rowsEven
112113
binlogEntry.DmlEvent.WhereColumnValues = sql.ToColumnValues(row)
113114
}
114115
}
115-
// The channel will do the throttling. Whoever is reding from the channel
116+
// The channel will do the throttling. Whoever is reading from the channel
116117
// decides whether action is taken synchronously (meaning we wait before
117118
// next iteration) or asynchronously (we keep pushing more events)
118119
// In reality, reads will be synchronous

go/cmd/gh-ost/main.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/github/gh-ost/go/base"
1616
"github.com/github/gh-ost/go/logic"
17+
_ "github.com/go-sql-driver/mysql"
1718
"github.com/outbrain/golib/log"
1819

1920
"golang.org/x/crypto/ssh/terminal"
@@ -54,6 +55,10 @@ func main() {
5455
flag.StringVar(&migrationContext.ConfigFile, "conf", "", "Config file")
5556
askPass := flag.Bool("ask-pass", false, "prompt for MySQL password")
5657

58+
flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL hosts")
59+
flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections to MySQL hosts. Requires --ssl")
60+
flag.BoolVar(&migrationContext.TLSAllowInsecure, "ssl-allow-insecure", false, "Skips verification of MySQL hosts' certificate chain and host name. Requires --ssl")
61+
5762
flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)")
5863
flag.StringVar(&migrationContext.OriginalTableName, "table", "", "table name (mandatory)")
5964
flag.StringVar(&migrationContext.AlterStatement, "alter", "", "alter statement (mandatory)")
@@ -110,6 +115,8 @@ func main() {
110115

111116
flag.StringVar(&migrationContext.HooksPath, "hooks-path", "", "directory where hook files are found (default: empty, ie. hooks disabled). Hook files found on this path, and conforming to hook naming conventions will be executed")
112117
flag.StringVar(&migrationContext.HooksHintMessage, "hooks-hint", "", "arbitrary message to be injected to hooks via GH_OST_HOOKS_HINT, for your convenience")
118+
flag.StringVar(&migrationContext.HooksHintOwner, "hooks-hint-owner", "", "arbitrary name of owner to be injected to hooks via GH_OST_HOOKS_HINT_OWNER, for your convenience")
119+
flag.StringVar(&migrationContext.HooksHintToken, "hooks-hint-token", "", "arbitrary token to be injected to hooks via GH_OST_HOOKS_HINT_TOKEN, for your convenience")
113120

114121
flag.UintVar(&migrationContext.ReplicaServerId, "replica-server-id", 99999, "server id used by gh-ost process. Default: 99999")
115122

@@ -195,6 +202,12 @@ func main() {
195202
if migrationContext.CliMasterPassword != "" && migrationContext.AssumeMasterHostname == "" {
196203
log.Fatalf("--master-password requires --assume-master-host")
197204
}
205+
if migrationContext.TLSCACertificate != "" && !migrationContext.UseTLS {
206+
log.Fatalf("--ssl-ca requires --ssl")
207+
}
208+
if migrationContext.TLSAllowInsecure && !migrationContext.UseTLS {
209+
log.Fatalf("--ssl-allow-insecure requires --ssl")
210+
}
198211
if *replicationLagQuery != "" {
199212
log.Warningf("--replication-lag-query is deprecated")
200213
}
@@ -239,6 +252,9 @@ func main() {
239252
migrationContext.SetThrottleHTTP(*throttleHTTP)
240253
migrationContext.SetDefaultNumRetries(*defaultRetries)
241254
migrationContext.ApplyCredentials()
255+
if err := migrationContext.SetupTLS(); err != nil {
256+
log.Fatale(err)
257+
}
242258
if err := migrationContext.SetCutOverLockTimeoutSeconds(*cutOverLockTimeoutSeconds); err != nil {
243259
log.Errore(err)
244260
}

go/logic/applier.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ func (this *Applier) InitDBConnections() (err error) {
7373
if this.db, _, err = mysql.GetDB(this.migrationContext.Uuid, applierUri); err != nil {
7474
return err
7575
}
76-
singletonApplierUri := fmt.Sprintf("%s?timeout=0", applierUri)
76+
singletonApplierUri := fmt.Sprintf("%s&timeout=0", applierUri)
7777
if this.singletonDB, _, err = mysql.GetDB(this.migrationContext.Uuid, singletonApplierUri); err != nil {
7878
return err
7979
}
@@ -126,7 +126,6 @@ func (this *Applier) readTableColumns() (err error) {
126126

127127
// showTableStatus returns the output of `show table status like '...'` command
128128
func (this *Applier) showTableStatus(tableName string) (rowMap sqlutils.RowMap) {
129-
rowMap = nil
130129
query := fmt.Sprintf(`show /* gh-ost */ table status from %s like '%s'`, sql.EscapeName(this.migrationContext.DatabaseName), tableName)
131130
sqlutils.QueryRowsMap(this.db, query, func(m sqlutils.RowMap) error {
132131
rowMap = m
@@ -482,6 +481,7 @@ func (this *Applier) ApplyIterationInsertQuery() (chunkSize int64, rowsAffected
482481
if err != nil {
483482
return nil, err
484483
}
484+
defer tx.Rollback()
485485
sessionQuery := fmt.Sprintf(`SET
486486
SESSION time_zone = '%s',
487487
sql_mode = CONCAT(@@session.sql_mode, ',STRICT_ALL_TABLES')
@@ -1001,15 +1001,19 @@ func (this *Applier) ApplyDMLEventQuery(dmlEvent *binlog.BinlogDMLEvent) error {
10011001
if err != nil {
10021002
return err
10031003
}
1004+
rollback := func(err error) error {
1005+
tx.Rollback()
1006+
return err
1007+
}
10041008
sessionQuery := `SET
10051009
SESSION time_zone = '+00:00',
10061010
sql_mode = CONCAT(@@session.sql_mode, ',STRICT_ALL_TABLES')
10071011
`
10081012
if _, err := tx.Exec(sessionQuery); err != nil {
1009-
return err
1013+
return rollback(err)
10101014
}
10111015
if _, err := tx.Exec(buildResult.query, buildResult.args...); err != nil {
1012-
return err
1016+
return rollback(err)
10131017
}
10141018
if err := tx.Commit(); err != nil {
10151019
return err

0 commit comments

Comments
 (0)