Skip to content

Commit

Permalink
fix(mysql): 修复 spider 集群可能的备份异常 #6647
Browse files Browse the repository at this point in the history
  • Loading branch information
seanlook authored and zhangzhw8 committed Sep 4, 2024
1 parent 3799cbb commit 363b58d
Show file tree
Hide file tree
Showing 12 changed files with 861 additions and 89 deletions.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Large diffs are not rendered by default.

23 changes: 22 additions & 1 deletion dbm-services/common/go-pubpkg/cmutil/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,31 @@ func ExecShellCommand(isSudo bool, param string) (stdoutStr string, err error) {
err = fmt.Errorf("execute shell command(%s) has stderr:%s", param, stderr.String())
return stderr.String(), err
}

return stdout.String(), nil
}

// ExecBashCommand stderr returned in error
// 如果 Run 返回 0,则error返回 nil,不检查 stderr
// 如果 Run 返回>0,则 error 返回 err.Error() 与 stderr 的结合
func ExecBashCommand(isSudo bool, cwd string, cmdStr string) (string, string, error) {
if isSudo {
cmdStr = "sudo " + cmdStr
}
var stdout, stderr bytes.Buffer
cmd := exec.Command("bash", "-c", cmdStr)
if cwd != "" {
cmd.Dir = cwd
}
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
// return stderr.String(), err
return stdout.String(), stderr.String(), err
}
return stdout.String(), "", nil
}

// ExecCommand bash=true: bash -c 'cmdName args', bash=false: ./cmdName args list
// ExecCommand(false, "df", "-k /data") will get `df '-k /data'` error command. you need change it to (false, "df", "-k", "/data") or (true, "df -k /data")
// bash=false need PATH
Expand Down
31 changes: 16 additions & 15 deletions dbm-services/common/go-pubpkg/mysqlcomm/hide_passowrd.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ package mysqlcomm

import (
"regexp"
"strings"
)

var (
mysqlRegex = regexp.MustCompile(`mysql.*-u(\s*)\w+.*\s-p(\S+).*`)
mysqlAdminRegex = regexp.MustCompile(`mysqladmin.*-u\w+.*\s-p(\S+).*`)
mysqlPasswordRegex = regexp.MustCompile(`\s-p[^\s]+`)
masterPasswordRegexp = regexp.MustCompile(`master_password="[^\s]*"`)
mysqlRegex = regexp.MustCompile(`(?i)mysql.*-u(\s*)\w+.*\s-p(\S+).*`)
mysqlAdminRegex = regexp.MustCompile(`(?i)mysqladmin.*-u\w+.*\s-p(\S+).*`)
mysqlPasswordRegex = regexp.MustCompile(`(?i)\s-p\S+`)
masterPasswordRegexp = regexp.MustCompile(`(?i)master_password="\S+"`)
// identifyByRegex identified by '' or IDENTIFIED WITH mysql_native_password BY 'aa'
identifyByRegex = regexp.MustCompile(`identified by '[^\s]*'`)
identifyWithByRegex = regexp.MustCompile(`identified (with.*password )?by '[^\s]*'`)
userPasswordRegex = regexp.MustCompile(`\s-u\w+.*\s-p(\S+).*`)
dsnRegex = regexp.MustCompile(`\w+:[^\s]*@tcp\([^\s]+\)`)
dsnPasswordRegex = regexp.MustCompile(`:[^\s]*@tcp\(`)
passwordRegex = regexp.MustCompile(`password ['|"]*\S+['|"]*`)
passwordGrantRegex = regexp.MustCompile(`password\(['|"]\S+['|"]\)`)
identifyByRegex = regexp.MustCompile(`(?i)identified by '\S+'`)
identifyWithByRegex = regexp.MustCompile(`(?i)identified (with.*password'? )?by '\S+'`)
identifyWithAsRegex = regexp.MustCompile(`(?i)identified (with.*password'? )?as '\S+'`)
userPasswordRegex = regexp.MustCompile(`(?i)\s-u\S+\s-p(\S+)`)
dsnRegex = regexp.MustCompile(`(?i)\w+:\S+@tcp\(\S+\)`)
dsnPasswordRegex = regexp.MustCompile(`:\S+@tcp\(`)
passwordRegex = regexp.MustCompile(`(?i)password ['"]?\S+['"]?`)
passwordGrantRegex = regexp.MustCompile(`(?i)password\(['"]?\S+['"]?\)`)
)

// ClearSensitiveInformation clear sensitive information from input
Expand All @@ -44,18 +44,19 @@ func ClearSensitiveInformation(input string) string {

// CleanSvrPassword TODO
func CleanSvrPassword(input string) string {
return passwordRegex.ReplaceAllString(strings.ToLower(input), "password 'xxxx'")
return passwordRegex.ReplaceAllString(input, "password 'xxxx'")
}

// CleanGrantPassword clean grant sql password
func CleanGrantPassword(input string) string {
return passwordGrantRegex.ReplaceAllString(strings.ToLower(input), "password('xxxx')")
return passwordGrantRegex.ReplaceAllString(input, "password('xxxx')")
}

// clearIdentifyByInSQL TODO
func clearIdentifyByInSQL(input string) string {
output := identifyByRegex.ReplaceAllString(strings.ToLower(input), `identified by 'xxxx'`)
output := identifyByRegex.ReplaceAllString(input, `identified by 'xxxx'`)
output = identifyWithByRegex.ReplaceAllString(output, "identified ${1}by 'xxxx'")
output = identifyWithAsRegex.ReplaceAllString(output, "identified ${1}as '*xxxx'")
return output
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -587,7 +587,6 @@ func (i *InstallMySQLComp) Install() (err error) {
var isSudo = mysqlutil.IsSudo()
for _, port := range i.InsPorts {
var initialMysql string
var output string
myCnf := util.GetMyCnfFileName(port)
initialLogFile := fmt.Sprintf("/tmp/install_mysql_%d.log", port)

Expand All @@ -610,9 +609,9 @@ func (i *InstallMySQLComp) Install() (err error) {
"su - mysql -c \"cd %s && ./bin/mysqld --defaults-file=%s --tc-admin=0 --initialize-insecure --user=mysql &>%s\"",
i.TdbctlInstallDir, myCnf, initialLogFile)
}

if output, err = osutil.ExecShellCommand(isSudo, initialMysql); err != nil {
logger.Error("%s execute failed, %s", initialMysql, output)
// 避免错误: /etc/profile: line 87: ulimit: open files: cannot modify limit: Operation not permitted
if _, errStr, err := cmutil.ExecBashCommand(isSudo, "", initialMysql); err != nil {
logger.Error("%s execute failed, err:%s, stderr:%s", initialMysql, err.Error(), errStr)
// 如果存在初始化的日志文件,才初始化错误的时间,将日志cat出来
if osutil.FileExist(initialLogFile) {
ldat, e := os.ReadFile(initialLogFile)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,15 +174,15 @@ func (c *InstallMysqlRotateBinlogComp) InstallCrontab() (err error) {

// RunMigrateOld 迁移老的 rotate_logbin 数据
func (c *InstallMysqlRotateBinlogComp) RunMigrateOld() (err error) {
chownCmd := fmt.Sprintf(`mkdir -p %s ; chown -R mysql.mysql %s ; chown -R mysql.mysql %s `,
cst.DBAReportBase, cst.DBAReportBase, c.installPath)
_, _ = osutil.ExecShellCommand(false, chownCmd)

cmdArgs := []string{"migrate-old", "-c", c.configFile}
_, stdErr, err := cmutil.ExecCommand(false, c.installPath, c.binPath, cmdArgs...)

chownCmd := fmt.Sprintf(`chown -R mysql.mysql %s ; mkdir -p %s ;chown -R mysql.mysql %s`, c.installPath,
cst.DBAReportBase, cst.DBAReportBase)
_, err = osutil.ExecShellCommand(false, chownCmd)

if err != nil {
logger.Error("migrate-old failed", err.Error())
logger.Error("migrate-old failed: %s", err.Error())
return errors.WithMessagef(err, "run migrate-old failed:%s", stdErr)
} else {
logger.Info("migrate-old success")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -334,49 +334,6 @@ func (i *InstallNewDbBackupComp) DecompressPkg() (err error) {
return nil
}

// InitBackupUserPriv 创建备份用户
// TODO 用户初始化考虑在部署 mysqld 的时候进行
func (i *InstallNewDbBackupComp) InitBackupUserPriv() (err error) {
if i.Params.UntarOnly {
logger.Info("untar_only=true do not need InitBackupUserPriv")
return nil
}
for _, port := range i.Params.Ports {
err := i.initPriv(port, false)
if err != nil {
return err
}

if i.Params.Role == cst.BackupRoleSpiderMaster {
err := i.initPriv(mysqlcomm.GetTdbctlPortBySpider(port), true)
if err != nil {
return err
}
}
}
return nil
}

func (i *InstallNewDbBackupComp) initPriv(port int, isTdbCtl bool) (err error) {
ver := i.versionMap[port]
privs := i.GeneralParam.RuntimeAccountParam.MySQLDbBackupAccount.GetAccountPrivs(ver, i.Params.Host)
var sqls []string
if isTdbCtl {
logger.Info("tdbctl port %d need tc_admin=0, binlog_format=off", port)
sqls = append(sqls, "set session tc_admin=0;", "set session sql_log_bin=off;")
}
sqls = append(sqls, privs.GenerateInitSql(ver)...)
dc, ok := i.dbConn[port]
if !ok {
return fmt.Errorf("from dbConns 获取%d连接失败", port)
}
if _, err = dc.ExecMore(sqls); err != nil {
logger.Error("初始化备份账户失败%s", err.Error())
return
}
return err
}

// GenerateDbbackupConfig TODO
func (i *InstallNewDbBackupComp) GenerateDbbackupConfig() (err error) {
if i.Params.UntarOnly {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,6 @@ func migrateBackupSchema(err error, db *sqlx.DB) error {
return errors.WithMessage(err, "recreate backupSchema failed")
}
}
logger.Log.Info("migrate table success: global_backup")
//logger.Log.Info("migrate table success: global_backup")
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,37 @@ func (g GlobalBackup) prepareBackup(tdbctlInst mysqlconn.InsObject) (string, []M
return backupId, backupServers, nil
}

// uniqMysqlServers servers 去重,但优先选择 remote master
func uniqMysqlServers(backupServers []MysqlServer) (servers []MysqlServer) {
uniqServer := map[string]string{}
for _, s := range backupServers {
if !strings.HasPrefix(s.ServerName, "SPT_SLAVE") {
key := fmt.Sprintf("%s:%d", s.Host, s.Port)
if _, ok := uniqServer[key]; !ok {
servers = append(servers, s)
uniqServer[key] = s.ServerName
}
}
}
for _, s := range backupServers {
if strings.HasPrefix(s.ServerName, "SPT_SLAVE") {
key := fmt.Sprintf("%s:%d", s.Host, s.Port)
if _, ok := uniqServer[key]; !ok {
servers = append(servers, s)
uniqServer[key] = s.ServerName
}
}
}
return
}

func (g GlobalBackup) initializeBackup(backupServers []MysqlServer, dbw *mysqlconn.DbWorker) error {
createdAt := time.Now().Format(time.DateTime)
sqlI := sq.Insert(g.GlobalBackupModel.TableName()).
Columns("ServerName", "Wrapper", "Host", "Port", "ShardValue", "BackupId", "BackupStatus", "CreatedAt")

// 这里要按照 ip:port 去重,以免出现重复记录
backupServers = uniqMysqlServers(backupServers)
for _, s := range backupServers {
if strings.HasPrefix(s.ServerName, "SPT_SLAVE") {
sqlI = sqlI.Values(s.ServerName, s.Wrapper, s.Host, s.Port, s.PartValue, g.BackupId,
Expand Down
2 changes: 1 addition & 1 deletion dbm-services/sqlserver/db-tools/dbactuator/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.4.2 // indirect
golang.org/x/crypto v0.9.0 // indirect
golang.org/x/crypto v0.9.0
golang.org/x/net v0.10.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
Expand Down
2 changes: 2 additions & 0 deletions dbm-services/sqlserver/db-tools/dbactuator/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,8 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA=
golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down

0 comments on commit 363b58d

Please sign in to comment.