Files
mayfly-go/server/internal/db/application/db_instance.go

295 lines
9.2 KiB
Go
Raw Normal View History

2023-08-27 11:07:29 +08:00
package application
import (
"context"
2024-04-12 13:24:20 +08:00
"mayfly-go/internal/common/consts"
"mayfly-go/internal/db/application/dto"
"mayfly-go/internal/db/dbm"
"mayfly-go/internal/db/dbm/dbi"
2023-08-27 11:07:29 +08:00
"mayfly-go/internal/db/domain/entity"
"mayfly-go/internal/db/domain/repository"
2024-11-20 22:43:53 +08:00
"mayfly-go/internal/db/imsg"
2024-04-12 13:24:20 +08:00
tagapp "mayfly-go/internal/tag/application"
tagdto "mayfly-go/internal/tag/application/dto"
2024-04-12 13:24:20 +08:00
tagentity "mayfly-go/internal/tag/domain/entity"
"mayfly-go/pkg/base"
"mayfly-go/pkg/errorx"
"mayfly-go/pkg/logx"
2023-08-27 11:07:29 +08:00
"mayfly-go/pkg/model"
"mayfly-go/pkg/utils/collx"
"mayfly-go/pkg/utils/stringx"
2024-04-12 13:24:20 +08:00
"mayfly-go/pkg/utils/structx"
2023-08-27 11:07:29 +08:00
)
type Instance interface {
base.App[*entity.DbInstance]
// GetPageList 分页获取数据库实例
GetPageList(condition *entity.InstanceQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error)
2023-08-27 11:07:29 +08:00
2024-04-12 13:24:20 +08:00
TestConn(instanceEntity *entity.DbInstance, authCert *tagentity.ResourceAuthCert) error
SaveDbInstance(ctx context.Context, instance *dto.SaveDbInstance) (uint64, error)
2023-08-27 11:07:29 +08:00
// Delete 删除数据库信息
Delete(ctx context.Context, id uint64) error
// GetDatabases 获取数据库实例的所有数据库列表
GetDatabases(entity *entity.DbInstance, authCert *tagentity.ResourceAuthCert) ([]string, error)
2024-04-12 13:24:20 +08:00
2024-05-16 17:26:32 +08:00
// GetDatabasesByAc 根据授权凭证名获取所有数据库名称列表
GetDatabasesByAc(acName string) ([]string, error)
2024-04-12 13:24:20 +08:00
// ToDbInfo 根据实例与授权凭证返回对应的DbInfo
ToDbInfo(instance *entity.DbInstance, authCertName string, database string) (*dbi.DbInfo, error)
2023-08-27 11:07:29 +08:00
}
type instanceAppImpl struct {
base.AppImpl[*entity.DbInstance, repository.Instance]
tagApp tagapp.TagTree `inject:"TagTreeApp"`
2024-04-12 13:24:20 +08:00
resourceAuthCertApp tagapp.ResourceAuthCert `inject:"ResourceAuthCertApp"`
dbApp Db `inject:"DbApp"`
2023-08-27 11:07:29 +08:00
}
2024-05-16 17:26:32 +08:00
var _ (Instance) = (*instanceAppImpl)(nil)
2024-01-21 22:52:20 +08:00
// 注入DbInstanceRepo
func (app *instanceAppImpl) InjectDbInstanceRepo(repo repository.Instance) {
app.Repo = repo
2024-01-21 22:52:20 +08:00
}
// GetPageList 分页获取数据库实例
func (app *instanceAppImpl) GetPageList(condition *entity.InstanceQuery, pageParam *model.PageParam, toEntity any, orderBy ...string) (*model.PageResult[any], error) {
return app.GetRepo().GetInstanceList(condition, pageParam, toEntity, orderBy...)
2023-08-27 11:07:29 +08:00
}
2024-04-12 13:24:20 +08:00
func (app *instanceAppImpl) TestConn(instanceEntity *entity.DbInstance, authCert *tagentity.ResourceAuthCert) error {
instanceEntity.Network = instanceEntity.GetNetwork()
2024-04-12 13:24:20 +08:00
authCert, err := app.resourceAuthCertApp.GetRealAuthCert(authCert)
if err != nil {
return err
2024-04-12 13:24:20 +08:00
}
dbConn, err := dbm.Conn(app.toDbInfoByAc(instanceEntity, authCert, ""))
if err != nil {
return err
}
dbConn.Close()
return nil
}
func (app *instanceAppImpl) SaveDbInstance(ctx context.Context, instance *dto.SaveDbInstance) (uint64, error) {
2024-04-12 13:24:20 +08:00
instanceEntity := instance.DbInstance
2023-08-27 11:07:29 +08:00
// 默认tcp连接
instanceEntity.Network = instanceEntity.GetNetwork()
2024-11-23 17:23:18 +08:00
resourceType := consts.ResourceTypeDbInstance
2024-04-12 13:24:20 +08:00
authCerts := instance.AuthCerts
tagCodePaths := instance.TagCodePaths
2024-04-12 13:24:20 +08:00
if len(authCerts) == 0 {
2024-11-20 22:43:53 +08:00
return 0, errorx.NewBiz("ac cannot be empty")
2024-04-12 13:24:20 +08:00
}
2023-08-27 11:07:29 +08:00
// 查找是否存在该库
oldInstance := &entity.DbInstance{
Host: instanceEntity.Host,
Port: instanceEntity.Port,
SshTunnelMachineId: instanceEntity.SshTunnelMachineId,
2023-08-27 11:07:29 +08:00
}
err := app.GetByCond(oldInstance)
2023-08-27 11:07:29 +08:00
if instanceEntity.Id == 0 {
if err == nil {
2024-11-20 22:43:53 +08:00
return 0, errorx.NewBizI(ctx, imsg.ErrDbInstExist)
2023-08-27 11:07:29 +08:00
}
instanceEntity.Code = stringx.Rand(10)
return instanceEntity.Id, app.Tx(ctx, func(ctx context.Context) error {
2024-04-12 13:24:20 +08:00
return app.Insert(ctx, instanceEntity)
}, func(ctx context.Context) error {
2024-05-16 17:26:32 +08:00
return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
2024-04-12 13:24:20 +08:00
ResourceCode: instanceEntity.Code,
ResourceType: tagentity.TagType(resourceType),
AuthCerts: authCerts,
})
}, func(ctx context.Context) error {
return app.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
ResourceTag: app.genDbInstanceResourceTag(instanceEntity, authCerts),
ParentTagCodePaths: tagCodePaths,
})
2024-04-12 13:24:20 +08:00
})
}
// 如果存在该库,则校验修改的库是否为该库
2024-04-23 11:35:45 +08:00
if err == nil {
if oldInstance.Id != instanceEntity.Id {
2024-11-20 22:43:53 +08:00
return 0, errorx.NewBizI(ctx, imsg.ErrDbInstExist)
2024-04-23 11:35:45 +08:00
}
} else {
// 根据host等未查到旧数据则需要根据id重新获取因为后续需要使用到code
2024-05-05 14:53:30 +08:00
oldInstance, err = app.GetById(instanceEntity.Id)
2024-04-23 11:35:45 +08:00
if err != nil {
2024-11-20 22:43:53 +08:00
return 0, errorx.NewBiz("db instance not found")
2024-04-23 11:35:45 +08:00
}
}
2024-04-23 11:35:45 +08:00
return oldInstance.Id, app.Tx(ctx, func(ctx context.Context) error {
2024-04-12 13:24:20 +08:00
return app.UpdateById(ctx, instanceEntity)
}, func(ctx context.Context) error {
2024-05-16 17:26:32 +08:00
return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
2024-04-12 13:24:20 +08:00
ResourceCode: oldInstance.Code,
ResourceType: tagentity.TagType(resourceType),
AuthCerts: authCerts,
})
}, func(ctx context.Context) error {
if instanceEntity.Name != oldInstance.Name {
2024-11-23 17:23:18 +08:00
if err := app.tagApp.UpdateTagName(ctx, tagentity.TagTypeDbInstance, oldInstance.Code, instanceEntity.Name); err != nil {
return err
}
}
return app.tagApp.SaveResourceTag(ctx, &tagdto.SaveResourceTag{
ResourceTag: app.genDbInstanceResourceTag(oldInstance, authCerts),
ParentTagCodePaths: tagCodePaths,
})
2024-04-12 13:24:20 +08:00
})
}
func (app *instanceAppImpl) Delete(ctx context.Context, instanceId uint64) error {
instance, err := app.GetById(instanceId)
2024-04-12 13:24:20 +08:00
if err != nil {
2024-11-20 22:43:53 +08:00
return errorx.NewBiz("db instnace not found")
}
2024-05-05 14:53:30 +08:00
dbs, _ := app.dbApp.ListByCond(&entity.Db{
InstanceId: instanceId,
2024-05-05 14:53:30 +08:00
})
2024-04-12 13:24:20 +08:00
return app.Tx(ctx, func(ctx context.Context) error {
return app.DeleteById(ctx, instanceId)
}, func(ctx context.Context) error {
// 删除该实例关联的授权凭证信息
2024-05-16 17:26:32 +08:00
return app.resourceAuthCertApp.RelateAuthCert(ctx, &tagdto.RelateAuthCert{
2024-04-12 13:24:20 +08:00
ResourceCode: instance.Code,
2024-11-23 17:23:18 +08:00
ResourceType: tagentity.TagType(consts.ResourceTypeDbInstance),
2024-04-12 13:24:20 +08:00
})
}, func(ctx context.Context) error {
return app.tagApp.DeleteTagByParam(ctx, &tagdto.DelResourceTag{
ResourceCode: instance.Code,
2024-11-23 17:23:18 +08:00
ResourceType: tagentity.TagType(consts.ResourceTypeDbInstance),
})
2024-05-05 14:53:30 +08:00
}, func(ctx context.Context) error {
// 删除所有库配置
for _, db := range dbs {
if err := app.dbApp.Delete(ctx, db.Id); err != nil {
return err
}
}
return nil
2024-04-12 13:24:20 +08:00
})
}
func (app *instanceAppImpl) GetDatabases(ed *entity.DbInstance, authCert *tagentity.ResourceAuthCert) ([]string, error) {
if authCert.Id != 0 {
// 密文可能被清除,故需要重新获取
authCert, _ = app.resourceAuthCertApp.GetAuthCert(authCert.Name)
} else {
if authCert.CiphertextType == tagentity.AuthCertCiphertextTypePublic {
publicAuthCert, err := app.resourceAuthCertApp.GetAuthCert(authCert.Ciphertext)
if err != nil {
return nil, err
}
authCert = publicAuthCert
}
2024-04-12 13:24:20 +08:00
}
2024-05-16 17:26:32 +08:00
return app.getDatabases(ed, authCert)
}
2024-05-16 17:26:32 +08:00
func (app *instanceAppImpl) GetDatabasesByAc(acName string) ([]string, error) {
ac, err := app.resourceAuthCertApp.GetAuthCert(acName)
if err != nil {
2024-11-20 22:43:53 +08:00
return nil, errorx.NewBiz("db ac not found")
}
2024-05-16 17:26:32 +08:00
instance := &entity.DbInstance{Code: ac.ResourceCode}
err = app.GetByCond(instance)
if err != nil {
2024-11-20 22:43:53 +08:00
return nil, errorx.NewBiz("the db instance information for this ac does not exist")
2024-05-16 17:26:32 +08:00
}
return app.getDatabases(instance, ac)
2023-08-27 11:07:29 +08:00
}
2024-04-12 13:24:20 +08:00
func (app *instanceAppImpl) ToDbInfo(instance *entity.DbInstance, authCertName string, database string) (*dbi.DbInfo, error) {
ac, err := app.resourceAuthCertApp.GetAuthCert(authCertName)
if err != nil {
return nil, err
}
return app.toDbInfoByAc(instance, ac, database), nil
}
2024-05-16 17:26:32 +08:00
func (app *instanceAppImpl) getDatabases(instance *entity.DbInstance, ac *tagentity.ResourceAuthCert) ([]string, error) {
instance.Network = instance.GetNetwork()
dbi := app.toDbInfoByAc(instance, ac, "")
dbConn, err := dbm.Conn(dbi)
if err != nil {
return nil, err
}
defer dbConn.Close()
return dbConn.GetMetadata().GetDbNames()
2024-05-16 17:26:32 +08:00
}
2024-04-12 13:24:20 +08:00
func (app *instanceAppImpl) toDbInfoByAc(instance *entity.DbInstance, ac *tagentity.ResourceAuthCert, database string) *dbi.DbInfo {
di := new(dbi.DbInfo)
di.InstanceId = instance.Id
di.Database = database
structx.Copy(di, instance)
di.Username = ac.Username
di.Password = ac.Ciphertext
return di
}
func (m *instanceAppImpl) genDbInstanceResourceTag(me *entity.DbInstance, authCerts []*tagentity.ResourceAuthCert) *tagdto.ResourceTag {
authCertTags := collx.ArrayMap[*tagentity.ResourceAuthCert, *tagdto.ResourceTag](authCerts, func(val *tagentity.ResourceAuthCert) *tagdto.ResourceTag {
return &tagdto.ResourceTag{
Code: val.Name,
Name: val.Username,
2024-11-26 17:32:44 +08:00
Type: tagentity.TagTypeAuthCert,
}
})
2024-05-05 14:53:30 +08:00
dbs, err := m.dbApp.ListByCond(&entity.Db{
InstanceId: me.Id,
2024-05-05 14:53:30 +08:00
})
if err != nil {
2024-11-20 22:43:53 +08:00
logx.Errorf("failed to retrieve the database associated with the instance: %v", err)
}
authCertName2DbTags := make(map[string][]*tagdto.ResourceTag)
for _, db := range dbs {
authCertName2DbTags[db.AuthCertName] = append(authCertName2DbTags[db.AuthCertName], &tagdto.ResourceTag{
Code: db.Code,
Name: db.Name,
2024-11-23 17:23:18 +08:00
Type: tagentity.TagTypeDb,
})
}
// 将数据库挂至授权凭证下
for _, ac := range authCertTags {
ac.Children = authCertName2DbTags[ac.Code]
}
return &tagdto.ResourceTag{
Code: me.Code,
2024-11-23 17:23:18 +08:00
Type: tagentity.TagTypeDbInstance,
Name: me.Name,
Children: authCertTags,
}
}