2016-04-18 17:59:34 +00:00
|
|
|
/*
|
|
|
|
Copyright 2016 GitHub Inc.
|
2016-05-16 09:09:17 +00:00
|
|
|
See https://github.com/github/gh-ost/blob/master/LICENSE
|
2016-04-18 17:59:34 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
package base
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2016-05-17 12:40:37 +00:00
|
|
|
"os"
|
2016-04-18 17:59:34 +00:00
|
|
|
"regexp"
|
2016-06-17 06:03:18 +00:00
|
|
|
"strings"
|
2016-04-18 17:59:34 +00:00
|
|
|
"time"
|
2017-09-06 18:25:35 +00:00
|
|
|
|
|
|
|
gosql "database/sql"
|
|
|
|
"github.com/github/gh-ost/go/mysql"
|
2016-04-18 17:59:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
prettifyDurationRegexp = regexp.MustCompile("([.][0-9]+)")
|
|
|
|
)
|
|
|
|
|
|
|
|
func PrettifyDurationOutput(d time.Duration) string {
|
|
|
|
if d < time.Second {
|
|
|
|
return "0s"
|
|
|
|
}
|
|
|
|
result := fmt.Sprintf("%s", d)
|
|
|
|
result = prettifyDurationRegexp.ReplaceAllString(result, "")
|
|
|
|
return result
|
|
|
|
}
|
2016-05-17 12:40:37 +00:00
|
|
|
|
|
|
|
func FileExists(fileName string) bool {
|
|
|
|
if _, err := os.Stat(fileName); err == nil {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
2016-06-17 06:03:18 +00:00
|
|
|
|
2017-05-07 11:58:18 +00:00
|
|
|
func TouchFile(fileName string) error {
|
|
|
|
f, err := os.OpenFile(fileName, os.O_APPEND|os.O_CREATE, 0755)
|
|
|
|
if err != nil {
|
2018-05-04 06:22:54 +00:00
|
|
|
return err
|
2017-05-07 11:58:18 +00:00
|
|
|
}
|
2018-05-04 06:22:54 +00:00
|
|
|
return f.Close()
|
2017-05-07 11:58:18 +00:00
|
|
|
}
|
|
|
|
|
2016-06-18 19:12:07 +00:00
|
|
|
// StringContainsAll returns true if `s` contains all non empty given `substrings`
|
|
|
|
// The function returns `false` if no non-empty arguments are given.
|
2016-06-17 06:03:18 +00:00
|
|
|
func StringContainsAll(s string, substrings ...string) bool {
|
|
|
|
nonEmptyStringsFound := false
|
|
|
|
for _, substring := range substrings {
|
2016-06-18 19:12:07 +00:00
|
|
|
if substring == "" {
|
2016-06-17 06:03:18 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
if strings.Contains(s, substring) {
|
|
|
|
nonEmptyStringsFound = true
|
|
|
|
} else {
|
|
|
|
// Immediate failure
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nonEmptyStringsFound
|
|
|
|
}
|
2017-09-06 18:25:35 +00:00
|
|
|
|
2018-03-29 03:19:20 +00:00
|
|
|
func ValidateConnection(db *gosql.DB, connectionConfig *mysql.ConnectionConfig, migrationContext *MigrationContext) (string, error) {
|
2018-01-23 05:51:41 +00:00
|
|
|
versionQuery := `select @@global.version`
|
2017-09-06 18:25:35 +00:00
|
|
|
var port, extraPort int
|
|
|
|
var version string
|
2018-01-23 05:51:41 +00:00
|
|
|
if err := db.QueryRow(versionQuery).Scan(&version); err != nil {
|
2017-09-06 18:25:35 +00:00
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
extraPortQuery := `select @@global.extra_port`
|
|
|
|
if err := db.QueryRow(extraPortQuery).Scan(&extraPort); err != nil {
|
|
|
|
// swallow this error. not all servers support extra_port
|
|
|
|
}
|
2018-01-23 05:51:41 +00:00
|
|
|
// AliyunRDS set users port to "NULL", replace it by gh-ost param
|
2018-09-02 06:51:40 +00:00
|
|
|
// GCP set users port to "NULL", replace it by gh-ost param
|
|
|
|
if migrationContext.AliyunRDS || migrationContext.GoogleCloudPlatform {
|
2018-01-23 05:51:41 +00:00
|
|
|
port = connectionConfig.Key.Port
|
|
|
|
} else {
|
|
|
|
portQuery := `select @@global.port`
|
|
|
|
if err := db.QueryRow(portQuery).Scan(&port); err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
}
|
2017-09-06 18:25:35 +00:00
|
|
|
|
|
|
|
if connectionConfig.Key.Port == port || (extraPort > 0 && connectionConfig.Key.Port == extraPort) {
|
2019-10-07 15:10:36 +00:00
|
|
|
migrationContext.Log.Infof("connection validated on %+v", connectionConfig.Key)
|
2017-09-06 18:25:35 +00:00
|
|
|
return version, nil
|
|
|
|
} else if extraPort == 0 {
|
|
|
|
return "", fmt.Errorf("Unexpected database port reported: %+v", port)
|
|
|
|
} else {
|
|
|
|
return "", fmt.Errorf("Unexpected database port reported: %+v / extra_port: %+v", port, extraPort)
|
|
|
|
}
|
|
|
|
}
|