package mysql import ( "context" "database/sql" "errors" "fmt" "strings" "time" "github.com/1Panel-dev/1Panel/agent/app/dto" "github.com/1Panel-dev/1Panel/agent/buserr" "github.com/1Panel-dev/1Panel/agent/global" "github.com/1Panel-dev/1Panel/agent/utils/mysql/client" ) type MysqlClient interface { Create(info client.CreateInfo) error CreateUser(info client.CreateInfo, withDeleteDB bool) error CreateUserOnly(info client.UserInfo, password string, timeout uint) error CreateDatabase(info client.CreateInfo) error DeleteDatabase(info client.DeleteInfo) error DeleteUser(info client.UserInfo, version string, timeout uint) error UpdateUser(info client.UserUpdateInfo, timeout uint) error GrantUser(info client.GrantInfo, timeout uint) error RevokeGrant(info client.GrantInfo, timeout uint) error ListUsers(timeout uint) ([]client.UserInfo, error) ListGrants(timeout uint) ([]client.GrantInfo, error) Delete(info client.DeleteInfo) error ChangePassword(info client.PasswordChangeInfo) error ChangeAccess(info client.AccessChangeInfo) error Backup(info client.BackupInfo) error Recover(info client.RecoverInfo) error LoadFormatCollation(timeout uint) ([]dto.MysqlFormatCollationOption, error) SyncDB(version string) ([]client.SyncDBInfo, error) Close() } func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) { if conn.From == "local" { mysqlCli := conn.Type if mysqlCli == "mysql-cluster" { mysqlCli = "mysql" } connArgs := []string{"exec", conn.Address, mysqlCli, "-u" + conn.Username, "-p" + conn.Password, "-e"} return client.NewLocal(connArgs, conn.Type, conn.Address, conn.Password, conn.Database), nil } if strings.Contains(conn.Address, ":") { conn.Address = fmt.Sprintf("[%s]", conn.Address) } tlsItem, err := client.ConnWithSSL(conn.SSL, conn.SkipVerify, conn.ClientKey, conn.ClientCert, conn.RootCert) if err != nil { return nil, err } connArgs := fmt.Sprintf("%s:%s@tcp(%s:%d)/?charset=utf8%s", conn.Username, conn.Password, conn.Address, conn.Port, tlsItem) db, err := sql.Open("mysql", connArgs) if err != nil { return nil, err } ctx, cancel := context.WithTimeout(context.Background(), time.Duration(conn.Timeout)*time.Second) defer cancel() if err := db.PingContext(ctx); err != nil { global.LOG.Errorf("test mysql conn failed, err: %v", err) return nil, err } if errors.Is(ctx.Err(), context.DeadlineExceeded) { return nil, buserr.New("ErrExecTimeOut") } return client.NewRemote(client.Remote{ Type: conn.Type, Client: db, Database: conn.Database, User: conn.Username, Password: conn.Password, Address: conn.Address, Port: conn.Port, SSL: conn.SSL, RootCert: conn.RootCert, ClientKey: conn.ClientKey, ClientCert: conn.ClientCert, SkipVerify: conn.SkipVerify, }), nil }