2022-10-20 18:45:47 +08:00
|
|
|
package service
|
|
|
|
|
|
|
|
import (
|
2022-11-18 17:50:52 +08:00
|
|
|
"context"
|
2022-10-21 18:50:38 +08:00
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2022-10-27 23:09:39 +08:00
|
|
|
"os"
|
2022-10-25 18:34:33 +08:00
|
|
|
"os/exec"
|
2023-07-27 15:52:25 +08:00
|
|
|
"path"
|
2022-11-04 19:02:15 +08:00
|
|
|
"regexp"
|
2022-10-24 18:46:19 +08:00
|
|
|
"strconv"
|
2022-10-25 18:34:33 +08:00
|
|
|
"strings"
|
2022-10-24 18:46:19 +08:00
|
|
|
"time"
|
2022-10-21 18:50:38 +08:00
|
|
|
|
2022-10-20 18:45:47 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
2022-10-25 18:34:33 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
2023-03-07 16:44:16 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/buserr"
|
2022-10-20 18:45:47 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
2022-10-27 23:09:39 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/global"
|
2023-07-17 16:34:29 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
2022-12-23 18:00:19 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
2022-11-04 19:02:15 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
2023-09-01 23:10:14 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/encrypt"
|
2023-07-20 17:51:57 +08:00
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/mysql"
|
|
|
|
"github.com/1Panel-dev/1Panel/backend/utils/mysql/client"
|
2022-10-21 18:50:38 +08:00
|
|
|
_ "github.com/go-sql-driver/mysql"
|
2022-10-20 18:45:47 +08:00
|
|
|
"github.com/jinzhu/copier"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
)
|
|
|
|
|
|
|
|
type MysqlService struct{}
|
|
|
|
|
|
|
|
type IMysqlService interface {
|
2023-07-24 14:55:26 +08:00
|
|
|
SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error)
|
2023-08-03 16:19:30 +08:00
|
|
|
ListDBOption() ([]dto.MysqlOption, error)
|
2022-12-28 18:35:53 +08:00
|
|
|
Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error)
|
2023-12-25 17:08:09 +08:00
|
|
|
BindUser(req dto.BindUser) error
|
2023-09-16 13:16:15 +08:00
|
|
|
LoadFromRemote(req dto.MysqlLoadDB) error
|
2022-12-08 19:07:32 +08:00
|
|
|
ChangeAccess(info dto.ChangeDBInfo) error
|
|
|
|
ChangePassword(info dto.ChangeDBInfo) error
|
2023-08-29 10:50:15 +08:00
|
|
|
UpdateVariables(req dto.MysqlVariablesUpdate) error
|
2023-02-13 15:48:18 +08:00
|
|
|
UpdateDescription(req dto.UpdateDescription) error
|
2023-08-29 10:50:15 +08:00
|
|
|
DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error)
|
2022-12-27 16:30:25 +08:00
|
|
|
Delete(ctx context.Context, req dto.MysqlDBDelete) error
|
2023-08-29 10:50:15 +08:00
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error)
|
|
|
|
LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error)
|
|
|
|
LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error)
|
2022-10-20 18:45:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewIMysqlService() IMysqlService {
|
|
|
|
return &MysqlService{}
|
|
|
|
}
|
|
|
|
|
2023-07-24 14:55:26 +08:00
|
|
|
func (u *MysqlService) SearchWithPage(search dto.MysqlDBSearch) (int64, interface{}, error) {
|
|
|
|
total, mysqls, err := mysqlRepo.Page(search.Page, search.PageSize,
|
2023-09-16 13:16:15 +08:00
|
|
|
mysqlRepo.WithByMysqlName(search.Database),
|
2023-07-24 14:55:26 +08:00
|
|
|
commonRepo.WithLikeName(search.Info),
|
|
|
|
commonRepo.WithOrderRuleBy(search.OrderBy, search.Order),
|
|
|
|
)
|
2022-10-20 18:45:47 +08:00
|
|
|
var dtoMysqls []dto.MysqlDBInfo
|
|
|
|
for _, mysql := range mysqls {
|
|
|
|
var item dto.MysqlDBInfo
|
|
|
|
if err := copier.Copy(&item, &mysql); err != nil {
|
|
|
|
return 0, nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
|
|
}
|
|
|
|
dtoMysqls = append(dtoMysqls, item)
|
|
|
|
}
|
|
|
|
return total, dtoMysqls, err
|
|
|
|
}
|
|
|
|
|
2023-08-03 16:19:30 +08:00
|
|
|
func (u *MysqlService) ListDBOption() ([]dto.MysqlOption, error) {
|
2022-11-18 16:14:23 +08:00
|
|
|
mysqls, err := mysqlRepo.List()
|
2023-09-11 18:28:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
databases, err := databaseRepo.GetList(databaseRepo.WithTypeList("mysql,mariadb"))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-08-03 16:19:30 +08:00
|
|
|
var dbs []dto.MysqlOption
|
2022-10-28 18:46:14 +08:00
|
|
|
for _, mysql := range mysqls {
|
2023-08-03 16:19:30 +08:00
|
|
|
var item dto.MysqlOption
|
|
|
|
if err := copier.Copy(&item, &mysql); err != nil {
|
|
|
|
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
item.Database = mysql.MysqlName
|
2023-09-11 18:28:19 +08:00
|
|
|
for _, database := range databases {
|
2023-09-16 13:16:15 +08:00
|
|
|
if database.Name == item.Database {
|
2023-09-11 18:28:19 +08:00
|
|
|
item.Type = database.Type
|
|
|
|
}
|
|
|
|
}
|
2023-08-03 16:19:30 +08:00
|
|
|
dbs = append(dbs, item)
|
2022-10-28 18:46:14 +08:00
|
|
|
}
|
2023-08-03 16:19:30 +08:00
|
|
|
return dbs, err
|
2022-10-28 18:46:14 +08:00
|
|
|
}
|
|
|
|
|
2022-12-28 18:35:53 +08:00
|
|
|
func (u *MysqlService) Create(ctx context.Context, req dto.MysqlDBCreate) (*model.DatabaseMysql, error) {
|
2023-07-17 16:34:29 +08:00
|
|
|
if cmd.CheckIllegal(req.Name, req.Username, req.Password, req.Format, req.Permission) {
|
|
|
|
return nil, buserr.New(constant.ErrCmdIllegal)
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
mysql, _ := mysqlRepo.Get(commonRepo.WithByName(req.Name), mysqlRepo.WithByMysqlName(req.Database), databaseRepo.WithByFrom(req.From))
|
2023-08-03 16:19:30 +08:00
|
|
|
if mysql.ID != 0 {
|
|
|
|
return nil, constant.ErrRecordExist
|
|
|
|
}
|
|
|
|
|
2023-07-20 17:51:57 +08:00
|
|
|
var createItem model.DatabaseMysql
|
|
|
|
if err := copier.Copy(&createItem, &req); err != nil {
|
|
|
|
return nil, errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
if req.From == "local" && req.Username == "root" {
|
2022-12-21 15:54:34 +08:00
|
|
|
return nil, errors.New("Cannot set root as user name")
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
2023-07-24 11:24:38 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2022-10-20 18:45:47 +08:00
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
createItem.MysqlName = req.Database
|
2023-07-21 18:28:45 +08:00
|
|
|
defer cli.Close()
|
2023-07-20 17:51:57 +08:00
|
|
|
if err := cli.Create(client.CreateInfo{
|
2023-07-21 18:28:45 +08:00
|
|
|
Name: req.Name,
|
|
|
|
Format: req.Format,
|
|
|
|
Username: req.Username,
|
|
|
|
Password: req.Password,
|
|
|
|
Permission: req.Permission,
|
|
|
|
Version: version,
|
|
|
|
Timeout: 300,
|
2023-07-20 17:51:57 +08:00
|
|
|
}); err != nil {
|
2022-12-21 15:54:34 +08:00
|
|
|
return nil, err
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
2022-12-28 18:35:53 +08:00
|
|
|
|
|
|
|
global.LOG.Infof("create database %s successful!", req.Name)
|
2023-07-20 17:51:57 +08:00
|
|
|
if err := mysqlRepo.Create(ctx, &createItem); err != nil {
|
2022-12-21 15:54:34 +08:00
|
|
|
return nil, err
|
2022-10-20 18:45:47 +08:00
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
return &createItem, nil
|
2022-10-20 18:45:47 +08:00
|
|
|
}
|
|
|
|
|
2023-12-25 17:08:09 +08:00
|
|
|
func (u *MysqlService) BindUser(req dto.BindUser) error {
|
|
|
|
dbItem, err := mysqlRepo.Get(mysqlRepo.WithByMysqlName(req.Database), commonRepo.WithByName(req.DB))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer cli.Close()
|
|
|
|
|
|
|
|
if err := cli.CreateUser(client.CreateInfo{
|
|
|
|
Name: dbItem.Name,
|
|
|
|
Format: dbItem.Format,
|
|
|
|
Username: req.Username,
|
|
|
|
Password: req.Password,
|
|
|
|
Permission: req.Permission,
|
|
|
|
Version: version,
|
|
|
|
Timeout: 300,
|
|
|
|
}, false); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
pass, err := encrypt.StringEncrypt(req.Password)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decrypt database db password failed, err: %v", err)
|
|
|
|
}
|
|
|
|
if err := mysqlRepo.Update(dbItem.ID, map[string]interface{}{
|
|
|
|
"username": req.Username,
|
|
|
|
"password": pass,
|
|
|
|
"permission": req.Permission,
|
|
|
|
}); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
func (u *MysqlService) LoadFromRemote(req dto.MysqlLoadDB) error {
|
|
|
|
client, version, err := LoadMysqlClientByFrom(req.Database)
|
2023-07-27 16:07:27 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-16 14:36:15 +08:00
|
|
|
databases, err := mysqlRepo.List(mysqlRepo.WithByMysqlName(req.Database))
|
2023-07-27 16:07:27 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
datas, err := client.SyncDB(version)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2024-03-14 18:22:07 +08:00
|
|
|
deleteList := databases
|
2023-07-27 16:07:27 +08:00
|
|
|
for _, data := range datas {
|
|
|
|
hasOld := false
|
2024-03-14 18:22:07 +08:00
|
|
|
for i := 0; i < len(databases); i++ {
|
|
|
|
if strings.EqualFold(databases[i].Name, data.Name) && strings.EqualFold(databases[i].MysqlName, data.MysqlName) {
|
2023-07-27 16:07:27 +08:00
|
|
|
hasOld = true
|
2024-06-28 15:30:59 +08:00
|
|
|
if databases[i].IsDelete {
|
|
|
|
_ = mysqlRepo.Update(databases[i].ID, map[string]interface{}{"is_delete": false})
|
|
|
|
}
|
2024-03-14 18:22:07 +08:00
|
|
|
deleteList = append(deleteList[:i], deleteList[i+1:]...)
|
2023-07-27 16:07:27 +08:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !hasOld {
|
|
|
|
var createItem model.DatabaseMysql
|
|
|
|
if err := copier.Copy(&createItem, &data); err != nil {
|
|
|
|
return errors.WithMessage(constant.ErrStructTransform, err.Error())
|
|
|
|
}
|
|
|
|
if err := mysqlRepo.Create(context.Background(), &createItem); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-03-14 18:22:07 +08:00
|
|
|
for _, delItem := range deleteList {
|
|
|
|
_ = mysqlRepo.Update(delItem.ID, map[string]interface{}{"is_delete": true})
|
|
|
|
}
|
2023-07-27 16:07:27 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-02-13 15:48:18 +08:00
|
|
|
func (u *MysqlService) UpdateDescription(req dto.UpdateDescription) error {
|
2022-12-24 13:31:30 +08:00
|
|
|
return mysqlRepo.Update(req.ID, map[string]interface{}{"description": req.Description})
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
func (u *MysqlService) DeleteCheck(req dto.MysqlDBDeleteCheck) ([]string, error) {
|
2022-12-04 17:28:03 +08:00
|
|
|
var appInUsed []string
|
2023-08-29 10:50:15 +08:00
|
|
|
db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
2022-12-04 17:28:03 +08:00
|
|
|
if err != nil {
|
|
|
|
return appInUsed, err
|
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
|
2023-07-27 16:07:27 +08:00
|
|
|
if db.From == "local" {
|
2023-09-16 13:16:15 +08:00
|
|
|
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
2023-07-27 16:07:27 +08:00
|
|
|
if err != nil {
|
|
|
|
return appInUsed, err
|
|
|
|
}
|
|
|
|
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(db.ID))
|
|
|
|
for _, app := range apps {
|
|
|
|
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
|
|
|
if appInstall.ID != 0 {
|
|
|
|
appInUsed = append(appInUsed, appInstall.Name)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2024-06-06 22:41:38 +08:00
|
|
|
apps, _ := appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(db.ID), appRepo.WithKey(req.Type))
|
2023-07-27 16:07:27 +08:00
|
|
|
for _, app := range apps {
|
|
|
|
appInstall, _ := appInstallRepo.GetFirst(commonRepo.WithByID(app.AppInstallId))
|
|
|
|
if appInstall.ID != 0 {
|
|
|
|
appInUsed = append(appInUsed, appInstall.Name)
|
|
|
|
}
|
2022-12-04 17:28:03 +08:00
|
|
|
}
|
|
|
|
}
|
2023-07-27 16:07:27 +08:00
|
|
|
|
2022-12-04 17:28:03 +08:00
|
|
|
return appInUsed, nil
|
|
|
|
}
|
|
|
|
|
2022-12-27 16:30:25 +08:00
|
|
|
func (u *MysqlService) Delete(ctx context.Context, req dto.MysqlDBDelete) error {
|
2022-12-26 14:47:08 +08:00
|
|
|
db, err := mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
|
|
|
if err != nil && !req.ForceDelete {
|
2022-10-24 18:46:19 +08:00
|
|
|
return err
|
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
2023-07-24 11:24:38 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer cli.Close()
|
2023-07-20 17:51:57 +08:00
|
|
|
if err := cli.Delete(client.DeleteInfo{
|
|
|
|
Name: db.Name,
|
|
|
|
Version: version,
|
|
|
|
Username: db.Username,
|
|
|
|
Permission: db.Permission,
|
|
|
|
Timeout: 300,
|
2023-08-23 17:16:18 +08:00
|
|
|
}); err != nil && !req.ForceDelete {
|
2023-07-20 17:51:57 +08:00
|
|
|
return err
|
2022-12-04 17:28:03 +08:00
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
|
2022-12-26 14:47:08 +08:00
|
|
|
if req.DeleteBackup {
|
2023-09-16 17:00:16 +08:00
|
|
|
uploadDir := path.Join(global.CONF.System.BaseDir, fmt.Sprintf("1panel/uploads/database/%s/%s/%s", req.Type, req.Database, db.Name))
|
|
|
|
if _, err := os.Stat(uploadDir); err == nil {
|
|
|
|
_ = os.RemoveAll(uploadDir)
|
|
|
|
}
|
2022-12-26 14:47:08 +08:00
|
|
|
localDir, err := loadLocalDir()
|
|
|
|
if err != nil && !req.ForceDelete {
|
|
|
|
return err
|
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
backupDir := path.Join(localDir, fmt.Sprintf("database/%s/%s/%s", req.Type, db.MysqlName, db.Name))
|
2022-12-26 14:47:08 +08:00
|
|
|
if _, err := os.Stat(backupDir); err == nil {
|
|
|
|
_ = os.RemoveAll(backupDir)
|
|
|
|
}
|
2023-09-16 17:00:16 +08:00
|
|
|
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(req.Type), commonRepo.WithByName(req.Database), backupRepo.WithByDetailName(db.Name))
|
2023-09-16 13:16:15 +08:00
|
|
|
global.LOG.Infof("delete database %s-%s backups successful", req.Database, db.Name)
|
2022-12-09 14:07:18 +08:00
|
|
|
}
|
|
|
|
|
2022-12-27 16:30:25 +08:00
|
|
|
_ = mysqlRepo.Delete(ctx, commonRepo.WithByID(db.ID))
|
2022-10-24 18:46:19 +08:00
|
|
|
return nil
|
2022-10-20 18:45:47 +08:00
|
|
|
}
|
2022-10-21 18:50:38 +08:00
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
func (u *MysqlService) ChangePassword(req dto.ChangeDBInfo) error {
|
|
|
|
if cmd.CheckIllegal(req.Value) {
|
2023-07-17 16:34:29 +08:00
|
|
|
return buserr.New(constant.ErrCmdIllegal)
|
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
2023-07-20 17:51:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-21 18:28:45 +08:00
|
|
|
defer cli.Close()
|
2022-10-25 18:34:33 +08:00
|
|
|
var (
|
2023-07-20 17:51:57 +08:00
|
|
|
mysqlData model.DatabaseMysql
|
|
|
|
passwordInfo client.PasswordChangeInfo
|
2022-10-25 18:34:33 +08:00
|
|
|
)
|
2023-08-29 10:50:15 +08:00
|
|
|
passwordInfo.Password = req.Value
|
2023-07-20 17:51:57 +08:00
|
|
|
passwordInfo.Timeout = 300
|
|
|
|
passwordInfo.Version = version
|
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
if req.ID != 0 {
|
|
|
|
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
2022-10-25 18:34:33 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
passwordInfo.Name = mysqlData.Name
|
|
|
|
passwordInfo.Username = mysqlData.Username
|
|
|
|
passwordInfo.Permission = mysqlData.Permission
|
|
|
|
} else {
|
|
|
|
passwordInfo.Username = "root"
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
if err := cli.ChangePassword(passwordInfo); err != nil {
|
2022-10-24 18:46:19 +08:00
|
|
|
return err
|
2022-10-21 18:50:38 +08:00
|
|
|
}
|
2022-12-08 19:07:32 +08:00
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
if req.ID != 0 {
|
2023-07-27 14:32:23 +08:00
|
|
|
var appRess []model.AppInstallResource
|
2023-08-29 10:50:15 +08:00
|
|
|
if req.From == "local" {
|
2023-09-16 13:16:15 +08:00
|
|
|
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
2023-07-27 14:32:23 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
appRess, _ = appInstallResourceRepo.GetBy(appInstallResourceRepo.WithLinkId(app.ID), appInstallResourceRepo.WithResourceId(mysqlData.ID))
|
|
|
|
} else {
|
|
|
|
appRess, _ = appInstallResourceRepo.GetBy(appInstallResourceRepo.WithResourceId(mysqlData.ID))
|
|
|
|
}
|
|
|
|
for _, appRes := range appRess {
|
|
|
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(appRes.AppInstallId))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
appModel, err := appRepo.GetFirst(commonRepo.WithByID(appInstall.AppId))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
global.LOG.Infof("start to update mysql password used by app %s-%s", appModel.Key, appInstall.Name)
|
2024-03-01 16:55:02 +08:00
|
|
|
if err := updateInstallInfoInDB(appModel.Key, appInstall.Name, "user-password", req.Value); err != nil {
|
2023-07-27 14:32:23 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
2023-09-13 17:32:12 +08:00
|
|
|
global.LOG.Info("execute password change sql successful")
|
2023-09-01 23:10:14 +08:00
|
|
|
pass, err := encrypt.StringEncrypt(req.Value)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decrypt database db password failed, err: %v", err)
|
|
|
|
}
|
|
|
|
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"password": pass})
|
2022-12-08 19:07:32 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-03-01 16:55:02 +08:00
|
|
|
if err := updateInstallInfoInDB(req.Type, req.Database, "password", req.Value); err != nil {
|
2022-12-12 19:04:45 +08:00
|
|
|
return err
|
|
|
|
}
|
2024-05-30 15:13:21 +08:00
|
|
|
if req.From == "local" {
|
|
|
|
remote, err := databaseRepo.Get(commonRepo.WithByName(req.Database))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
pass, err := encrypt.StringEncrypt(req.Value)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("decrypt database password failed, err: %v", err)
|
|
|
|
}
|
|
|
|
_ = databaseRepo.Update(remote.ID, map[string]interface{}{"password": pass})
|
|
|
|
}
|
2022-12-08 19:07:32 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
func (u *MysqlService) ChangeAccess(req dto.ChangeDBInfo) error {
|
|
|
|
if cmd.CheckIllegal(req.Value) {
|
2023-07-17 16:34:29 +08:00
|
|
|
return buserr.New(constant.ErrCmdIllegal)
|
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
cli, version, err := LoadMysqlClientByFrom(req.Database)
|
2023-07-20 17:51:57 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2023-07-21 18:28:45 +08:00
|
|
|
defer cli.Close()
|
2022-12-08 19:07:32 +08:00
|
|
|
var (
|
2023-07-20 17:51:57 +08:00
|
|
|
mysqlData model.DatabaseMysql
|
|
|
|
accessInfo client.AccessChangeInfo
|
2022-12-08 19:07:32 +08:00
|
|
|
)
|
2023-08-29 10:50:15 +08:00
|
|
|
accessInfo.Permission = req.Value
|
2023-07-20 17:51:57 +08:00
|
|
|
accessInfo.Timeout = 300
|
|
|
|
accessInfo.Version = version
|
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
if req.ID != 0 {
|
|
|
|
mysqlData, err = mysqlRepo.Get(commonRepo.WithByID(req.ID))
|
2022-10-25 18:34:33 +08:00
|
|
|
if err != nil {
|
2022-10-24 18:46:19 +08:00
|
|
|
return err
|
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
accessInfo.Name = mysqlData.Name
|
|
|
|
accessInfo.Username = mysqlData.Username
|
2023-07-21 18:28:45 +08:00
|
|
|
accessInfo.Password = mysqlData.Password
|
2023-07-20 17:51:57 +08:00
|
|
|
accessInfo.OldPermission = mysqlData.Permission
|
|
|
|
} else {
|
|
|
|
accessInfo.Username = "root"
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
if err := cli.ChangeAccess(accessInfo); err != nil {
|
2022-12-08 19:07:32 +08:00
|
|
|
return err
|
|
|
|
}
|
2022-10-25 18:34:33 +08:00
|
|
|
|
2023-07-20 17:51:57 +08:00
|
|
|
if mysqlData.ID != 0 {
|
2023-08-29 10:50:15 +08:00
|
|
|
_ = mysqlRepo.Update(mysqlData.ID, map[string]interface{}{"permission": req.Value})
|
2022-10-25 18:34:33 +08:00
|
|
|
}
|
2023-05-12 17:48:31 +08:00
|
|
|
|
2022-10-24 18:46:19 +08:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-08-29 10:50:15 +08:00
|
|
|
func (u *MysqlService) UpdateVariables(req dto.MysqlVariablesUpdate) error {
|
2023-09-16 13:16:15 +08:00
|
|
|
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Database)
|
2022-10-25 11:41:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-11-04 19:02:15 +08:00
|
|
|
var files []string
|
2022-10-25 11:41:19 +08:00
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
path := fmt.Sprintf("%s/%s/%s/conf/my.cnf", constant.AppInstallDir, req.Type, app.Name)
|
2023-04-07 11:30:10 +08:00
|
|
|
lineBytes, err := os.ReadFile(path)
|
2022-11-04 19:02:15 +08:00
|
|
|
if err != nil {
|
2022-10-25 11:41:19 +08:00
|
|
|
return err
|
2022-11-04 19:02:15 +08:00
|
|
|
}
|
2022-12-21 16:21:28 +08:00
|
|
|
files = strings.Split(string(lineBytes), "\n")
|
|
|
|
|
2022-12-08 18:09:14 +08:00
|
|
|
group := "[mysqld]"
|
2023-08-29 10:50:15 +08:00
|
|
|
for _, info := range req.Variables {
|
2023-09-16 13:16:15 +08:00
|
|
|
if !strings.HasPrefix(app.Version, "5.7") && !strings.HasPrefix(app.Version, "5.6") {
|
2022-12-09 14:07:18 +08:00
|
|
|
if info.Param == "query_cache_size" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-23 18:00:19 +08:00
|
|
|
if _, ok := info.Value.(float64); ok {
|
|
|
|
files = updateMyCnf(files, group, info.Param, common.LoadSizeUnit(info.Value.(float64)))
|
2022-12-20 15:23:48 +08:00
|
|
|
} else {
|
|
|
|
files = updateMyCnf(files, group, info.Param, info.Value)
|
|
|
|
}
|
2022-10-25 11:41:19 +08:00
|
|
|
}
|
2022-12-12 14:06:39 +08:00
|
|
|
file, err := os.OpenFile(path, os.O_WRONLY|os.O_TRUNC, 0666)
|
2022-11-04 19:02:15 +08:00
|
|
|
if err != nil {
|
2022-10-25 11:41:19 +08:00
|
|
|
return err
|
|
|
|
}
|
2022-11-04 19:02:15 +08:00
|
|
|
defer file.Close()
|
|
|
|
_, err = file.WriteString(strings.Join(files, "\n"))
|
|
|
|
if err != nil {
|
2022-10-25 11:41:19 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Type, app.Name)); err != nil {
|
2022-10-25 11:41:19 +08:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
func (u *MysqlService) LoadRemoteAccess(req dto.OperationWithNameAndType) (bool, error) {
|
|
|
|
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
2022-12-09 14:07:18 +08:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2024-04-23 17:59:00 +08:00
|
|
|
hosts, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "select host from mysql.user where user='root';")
|
2022-10-25 18:34:33 +08:00
|
|
|
if err != nil {
|
2022-12-09 14:07:18 +08:00
|
|
|
return false, err
|
2022-10-25 18:34:33 +08:00
|
|
|
}
|
|
|
|
for _, host := range hosts {
|
|
|
|
if host == "%" {
|
2022-12-09 14:07:18 +08:00
|
|
|
return true, nil
|
2022-10-25 18:34:33 +08:00
|
|
|
}
|
|
|
|
}
|
2022-12-09 14:07:18 +08:00
|
|
|
|
|
|
|
return false, nil
|
2022-10-25 18:34:33 +08:00
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
func (u *MysqlService) LoadVariables(req dto.OperationWithNameAndType) (*dto.MysqlVariables, error) {
|
|
|
|
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
2022-10-25 18:34:33 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2024-04-23 17:59:00 +08:00
|
|
|
variableMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global variables;")
|
2022-10-24 18:46:19 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
var info dto.MysqlVariables
|
2022-10-21 18:50:38 +08:00
|
|
|
arr, err := json.Marshal(variableMap)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = json.Unmarshal(arr, &info)
|
|
|
|
return &info, nil
|
|
|
|
}
|
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
func (u *MysqlService) LoadStatus(req dto.OperationWithNameAndType) (*dto.MysqlStatus, error) {
|
|
|
|
app, err := appInstallRepo.LoadBaseInfo(req.Type, req.Name)
|
2022-10-21 18:50:38 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-04-23 17:59:00 +08:00
|
|
|
statusMap, err := executeSqlForMaps(app.ContainerName, app.Key, app.Password, "show global status;")
|
2022-10-21 18:50:38 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-10-25 18:34:33 +08:00
|
|
|
|
2022-10-21 18:50:38 +08:00
|
|
|
var info dto.MysqlStatus
|
2022-10-25 18:34:33 +08:00
|
|
|
arr, err := json.Marshal(statusMap)
|
2022-10-21 18:50:38 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
_ = json.Unmarshal(arr, &info)
|
2022-10-24 18:46:19 +08:00
|
|
|
|
2022-10-25 18:34:33 +08:00
|
|
|
if value, ok := statusMap["Run"]; ok {
|
2022-10-24 18:46:19 +08:00
|
|
|
uptime, _ := strconv.Atoi(value)
|
2024-06-28 14:04:08 +08:00
|
|
|
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format(constant.DateTimeLayout)
|
2022-10-24 18:46:19 +08:00
|
|
|
} else {
|
2022-10-25 18:34:33 +08:00
|
|
|
if value, ok := statusMap["Uptime"]; ok {
|
2022-10-24 18:46:19 +08:00
|
|
|
uptime, _ := strconv.Atoi(value)
|
2024-06-28 14:04:08 +08:00
|
|
|
info.Run = time.Unix(time.Now().Unix()-int64(uptime), 0).Format(constant.DateTimeLayout)
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-10-25 18:34:33 +08:00
|
|
|
info.File = "OFF"
|
|
|
|
info.Position = "OFF"
|
2024-04-23 17:59:00 +08:00
|
|
|
rows, err := executeSqlForRows(app.ContainerName, app.Key, app.Password, "show master status;")
|
2022-10-25 18:34:33 +08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if len(rows) > 2 {
|
|
|
|
itemValue := strings.Split(rows[1], "\t")
|
|
|
|
if len(itemValue) > 2 {
|
|
|
|
info.File = itemValue[0]
|
|
|
|
info.Position = itemValue[1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &info, nil
|
|
|
|
}
|
|
|
|
|
2024-04-23 17:59:00 +08:00
|
|
|
func executeSqlForMaps(containerName, dbType, password, command string) (map[string]string, error) {
|
|
|
|
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
2023-02-15 18:05:23 +08:00
|
|
|
stdout, err := cmd.CombinedOutput()
|
2022-10-27 23:09:39 +08:00
|
|
|
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
|
|
|
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
|
|
|
return nil, errors.New(stdStr)
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
2022-10-25 18:34:33 +08:00
|
|
|
|
|
|
|
rows := strings.Split(stdStr, "\n")
|
|
|
|
rowMap := make(map[string]string)
|
|
|
|
for _, v := range rows {
|
|
|
|
itemRow := strings.Split(v, "\t")
|
|
|
|
if len(itemRow) == 2 {
|
|
|
|
rowMap[itemRow[0]] = itemRow[1]
|
2022-10-24 18:46:19 +08:00
|
|
|
}
|
|
|
|
}
|
2022-10-25 18:34:33 +08:00
|
|
|
return rowMap, nil
|
|
|
|
}
|
|
|
|
|
2024-04-23 17:59:00 +08:00
|
|
|
func executeSqlForRows(containerName, dbType, password, command string) ([]string, error) {
|
|
|
|
cmd := exec.Command("docker", "exec", containerName, dbType, "-uroot", "-p"+password, "-e", command)
|
2023-02-15 18:05:23 +08:00
|
|
|
stdout, err := cmd.CombinedOutput()
|
2022-10-25 18:34:33 +08:00
|
|
|
stdStr := strings.ReplaceAll(string(stdout), "mysql: [Warning] Using a password on the command line interface can be insecure.\n", "")
|
2022-10-27 23:09:39 +08:00
|
|
|
if err != nil || strings.HasPrefix(string(stdStr), "ERROR ") {
|
|
|
|
return nil, errors.New(stdStr)
|
|
|
|
}
|
2022-10-25 18:34:33 +08:00
|
|
|
return strings.Split(stdStr, "\n"), nil
|
|
|
|
}
|
|
|
|
|
2022-11-04 19:02:15 +08:00
|
|
|
func updateMyCnf(oldFiles []string, group string, param string, value interface{}) []string {
|
|
|
|
isOn := false
|
2022-11-09 15:08:38 +08:00
|
|
|
hasGroup := false
|
2022-11-04 19:02:15 +08:00
|
|
|
hasKey := false
|
|
|
|
regItem, _ := regexp.Compile(`\[*\]`)
|
|
|
|
var newFiles []string
|
2022-11-09 15:08:38 +08:00
|
|
|
i := 0
|
2022-11-04 19:02:15 +08:00
|
|
|
for _, line := range oldFiles {
|
2022-11-09 15:08:38 +08:00
|
|
|
i++
|
2022-11-04 19:02:15 +08:00
|
|
|
if strings.HasPrefix(line, group) {
|
|
|
|
isOn = true
|
2022-11-09 15:08:38 +08:00
|
|
|
hasGroup = true
|
2022-11-04 19:02:15 +08:00
|
|
|
newFiles = append(newFiles, line)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if !isOn {
|
|
|
|
newFiles = append(newFiles, line)
|
|
|
|
continue
|
|
|
|
}
|
2023-03-07 18:20:52 +08:00
|
|
|
if strings.HasPrefix(line, param+"=") || strings.HasPrefix(line, "# "+param+"=") {
|
2022-11-04 19:02:15 +08:00
|
|
|
newFiles = append(newFiles, fmt.Sprintf("%s=%v", param, value))
|
|
|
|
hasKey = true
|
|
|
|
continue
|
|
|
|
}
|
2022-11-09 15:08:38 +08:00
|
|
|
if regItem.Match([]byte(line)) || i == len(oldFiles) {
|
|
|
|
isOn = false
|
|
|
|
if !hasKey {
|
|
|
|
newFiles = append(newFiles, fmt.Sprintf("%s=%v", param, value))
|
|
|
|
}
|
2022-11-04 19:02:15 +08:00
|
|
|
newFiles = append(newFiles, line)
|
|
|
|
continue
|
|
|
|
}
|
2022-11-09 15:08:38 +08:00
|
|
|
newFiles = append(newFiles, line)
|
2022-11-04 19:02:15 +08:00
|
|
|
}
|
2022-11-09 15:08:38 +08:00
|
|
|
if !hasGroup {
|
2022-11-04 19:02:15 +08:00
|
|
|
newFiles = append(newFiles, group+"\n")
|
|
|
|
newFiles = append(newFiles, fmt.Sprintf("%s=%v\n", param, value))
|
|
|
|
}
|
|
|
|
return newFiles
|
|
|
|
}
|
2023-07-20 17:51:57 +08:00
|
|
|
|
2023-09-16 13:16:15 +08:00
|
|
|
func LoadMysqlClientByFrom(database string) (mysql.MysqlClient, string, error) {
|
2023-07-20 17:51:57 +08:00
|
|
|
var (
|
2023-07-24 11:24:38 +08:00
|
|
|
dbInfo client.DBInfo
|
|
|
|
version string
|
|
|
|
err error
|
2023-07-20 17:51:57 +08:00
|
|
|
)
|
2023-07-21 18:28:45 +08:00
|
|
|
|
2023-07-27 14:32:23 +08:00
|
|
|
dbInfo.Timeout = 300
|
2023-09-16 13:16:15 +08:00
|
|
|
databaseItem, err := databaseRepo.Get(commonRepo.WithByName(database))
|
2023-08-29 10:50:15 +08:00
|
|
|
if err != nil {
|
2023-09-16 13:16:15 +08:00
|
|
|
return nil, "", err
|
2023-08-29 10:50:15 +08:00
|
|
|
}
|
2024-04-23 17:59:00 +08:00
|
|
|
dbInfo.Type = databaseItem.Type
|
2023-08-29 10:50:15 +08:00
|
|
|
dbInfo.From = databaseItem.From
|
2023-09-16 13:16:15 +08:00
|
|
|
dbInfo.Database = database
|
2023-08-29 10:50:15 +08:00
|
|
|
if dbInfo.From != "local" {
|
2023-07-20 17:51:57 +08:00
|
|
|
dbInfo.Address = databaseItem.Address
|
|
|
|
dbInfo.Port = databaseItem.Port
|
|
|
|
dbInfo.Username = databaseItem.Username
|
|
|
|
dbInfo.Password = databaseItem.Password
|
2023-11-29 10:46:07 +08:00
|
|
|
dbInfo.SSL = databaseItem.SSL
|
|
|
|
dbInfo.ClientKey = databaseItem.ClientKey
|
|
|
|
dbInfo.ClientCert = databaseItem.ClientCert
|
|
|
|
dbInfo.RootCert = databaseItem.RootCert
|
|
|
|
dbInfo.SkipVerify = databaseItem.SkipVerify
|
2023-07-20 17:51:57 +08:00
|
|
|
version = databaseItem.Version
|
|
|
|
|
|
|
|
} else {
|
2023-09-16 13:16:15 +08:00
|
|
|
app, err := appInstallRepo.LoadBaseInfo(databaseItem.Type, database)
|
2023-07-20 17:51:57 +08:00
|
|
|
if err != nil {
|
2023-09-16 13:16:15 +08:00
|
|
|
return nil, "", err
|
2023-07-20 17:51:57 +08:00
|
|
|
}
|
|
|
|
dbInfo.Address = app.ContainerName
|
|
|
|
dbInfo.Username = "root"
|
|
|
|
dbInfo.Password = app.Password
|
|
|
|
version = app.Version
|
|
|
|
}
|
|
|
|
|
|
|
|
cli, err := mysql.NewMysqlClient(dbInfo)
|
|
|
|
if err != nil {
|
2023-09-16 13:16:15 +08:00
|
|
|
return nil, "", err
|
2023-07-20 17:51:57 +08:00
|
|
|
}
|
2023-09-16 13:16:15 +08:00
|
|
|
return cli, version, nil
|
2023-07-20 17:51:57 +08:00
|
|
|
}
|