diff --git a/backend/app/api/v1/remote_db.go b/backend/app/api/v1/remote_db.go index ecf8d0739..e0b2f046e 100644 --- a/backend/app/api/v1/remote_db.go +++ b/backend/app/api/v1/remote_db.go @@ -34,6 +34,28 @@ func (b *BaseApi) CreateRemoteDB(c *gin.Context) { helper.SuccessWithData(c, nil) } +// @Tags Database +// @Summary Check remote database +// @Description 检测远程数据库连接性 +// @Accept json +// @Param request body dto.RemoteDBCreate true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /databases/remote/check [post] +// @x-panel-log {"bodyKeys":["name", "type"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测远程数据库 [name][type] 连接性","formatEN":"check if remote database [name][type] is connectable"} +func (b *BaseApi) CheckeRemoteDB(c *gin.Context) { + var req dto.RemoteDBCreate + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + helper.SuccessWithData(c, remoteDBService.CheckeRemoteDB(req)) +} + // @Tags Database // @Summary Page remote databases // @Description 获取远程数据库列表分页 diff --git a/backend/app/service/remote_db.go b/backend/app/service/remote_db.go index 61219df75..64bf129c7 100644 --- a/backend/app/service/remote_db.go +++ b/backend/app/service/remote_db.go @@ -16,6 +16,7 @@ type RemoteDBService struct{} type IRemoteDBService interface { Get(name string) (dto.RemoteDBInfo, error) SearchWithPage(search dto.RemoteDBSearch) (int64, interface{}, error) + CheckeRemoteDB(req dto.RemoteDBCreate) bool Create(req dto.RemoteDBCreate) error Update(req dto.RemoteDBUpdate) error Delete(id uint) error @@ -68,6 +69,20 @@ func (u *RemoteDBService) List(dbType string) ([]dto.RemoteDBOption, error) { return datas, err } +func (u *RemoteDBService) CheckeRemoteDB(req dto.RemoteDBCreate) bool { + if _, err := mysql.NewMysqlClient(client.DBInfo{ + From: "remote", + Address: req.Address, + Port: req.Port, + Username: req.Username, + Password: req.Password, + Timeout: 6, + }); err != nil { + return false + } + return true +} + func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error { db, _ := remoteDBRepo.Get(commonRepo.WithByName(req.Name)) if db.ID != 0 { @@ -79,7 +94,7 @@ func (u *RemoteDBService) Create(req dto.RemoteDBCreate) error { Port: req.Port, Username: req.Username, Password: req.Password, - Timeout: 300, + Timeout: 6, }); err != nil { return err } diff --git a/backend/router/ro_database.go b/backend/router/ro_database.go index cc56e5024..eeaf8f0c9 100644 --- a/backend/router/ro_database.go +++ b/backend/router/ro_database.go @@ -43,6 +43,7 @@ func (s *DatabaseRouter) InitDatabaseRouter(Router *gin.RouterGroup) { cmdRouter.POST("/redis/conffile/update", baseApi.UpdateRedisConfByFile) cmdRouter.POST("/redis/persistence/update", baseApi.UpdateRedisPersistenceConf) + cmdRouter.POST("/remote/check", baseApi.CheckeRemoteDB) cmdRouter.POST("/remote", baseApi.CreateRemoteDB) cmdRouter.GET("/remote/:name", baseApi.GetRemoteDB) cmdRouter.GET("/remote/list/:type", baseApi.ListRemoteDB) diff --git a/backend/utils/mysql/client.go b/backend/utils/mysql/client.go index 18fce53cb..75e9a9465 100644 --- a/backend/utils/mysql/client.go +++ b/backend/utils/mysql/client.go @@ -1,8 +1,10 @@ package mysql import ( + "context" "database/sql" "fmt" + "time" "github.com/1Panel-dev/1Panel/backend/buserr" "github.com/1Panel-dev/1Panel/backend/constant" @@ -38,9 +40,16 @@ func NewMysqlClient(conn client.DBInfo) (MysqlClient, error) { if err != nil { return nil, err } - if err := db.Ping(); err != nil { + + ctx, cancel := context.WithTimeout(context.Background(), time.Duration(conn.Timeout)*time.Second) + defer cancel() + if err := db.PingContext(ctx); err != nil { return nil, err } + if ctx.Err() == context.DeadlineExceeded { + return nil, buserr.New(constant.ErrExecTimeOut) + } + return client.NewRemote(client.Remote{ Client: db, From: conn.From, diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 56de16255..53fbfa0f4 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -4410,6 +4410,49 @@ const docTemplate = `{ } } }, + "/databases/remote/check": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "检测远程数据库连接性", + "consumes": [ + "application/json" + ], + "tags": [ + "Database" + ], + "summary": "Check remote database", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.RemoteDBCreate" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "name", + "type" + ], + "formatEN": "check if remote database [name][type] is connectable", + "formatZH": "检测远程数据库 [name][type] 连接性", + "paramKeys": [] + } + } + }, "/databases/remote/del": { "post": { "security": [ @@ -11621,7 +11664,6 @@ const docTemplate = `{ "dto.ChangeDBInfo": { "type": "object", "required": [ - "from", "value" ], "properties": { @@ -12923,13 +12965,15 @@ const docTemplate = `{ "type": "integer" }, "password": { - "type": "string" + "type": "string", + "maxLength": 256 }, "protocol": { "type": "string" }, "username": { - "type": "string" + "type": "string", + "maxLength": 256 } } }, @@ -13776,7 +13820,8 @@ const docTemplate = `{ ] }, "name": { - "type": "string" + "type": "string", + "maxLength": 256 }, "password": { "type": "string" @@ -13817,7 +13862,8 @@ const docTemplate = `{ "type": "integer" }, "name": { - "type": "string" + "type": "string", + "maxLength": 256 }, "password": { "type": "string" diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 4b4f1a0eb..3d49d92fc 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -4403,6 +4403,49 @@ } } }, + "/databases/remote/check": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "检测远程数据库连接性", + "consumes": [ + "application/json" + ], + "tags": [ + "Database" + ], + "summary": "Check remote database", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.RemoteDBCreate" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFuntions": [], + "bodyKeys": [ + "name", + "type" + ], + "formatEN": "check if remote database [name][type] is connectable", + "formatZH": "检测远程数据库 [name][type] 连接性", + "paramKeys": [] + } + } + }, "/databases/remote/del": { "post": { "security": [ @@ -11614,7 +11657,6 @@ "dto.ChangeDBInfo": { "type": "object", "required": [ - "from", "value" ], "properties": { @@ -12916,13 +12958,15 @@ "type": "integer" }, "password": { - "type": "string" + "type": "string", + "maxLength": 256 }, "protocol": { "type": "string" }, "username": { - "type": "string" + "type": "string", + "maxLength": 256 } } }, @@ -13769,7 +13813,8 @@ ] }, "name": { - "type": "string" + "type": "string", + "maxLength": 256 }, "password": { "type": "string" @@ -13810,7 +13855,8 @@ "type": "integer" }, "name": { - "type": "string" + "type": "string", + "maxLength": 256 }, "password": { "type": "string" diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index d8092371b..8182f10f1 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -127,7 +127,6 @@ definitions: value: type: string required: - - from - value type: object dto.ChangeHostGroup: @@ -1000,10 +999,12 @@ definitions: id: type: integer password: + maxLength: 256 type: string protocol: type: string username: + maxLength: 256 type: string type: object dto.ImageSave: @@ -1565,6 +1566,7 @@ definitions: - remote type: string name: + maxLength: 256 type: string password: type: string @@ -1599,6 +1601,7 @@ definitions: id: type: integer name: + maxLength: 256 type: string password: type: string @@ -6648,6 +6651,34 @@ paths: summary: Get remote databases tags: - Database + /databases/remote/check: + post: + consumes: + - application/json + description: 检测远程数据库连接性 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.RemoteDBCreate' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Check remote database + tags: + - Database + x-panel-log: + BeforeFuntions: [] + bodyKeys: + - name + - type + formatEN: check if remote database [name][type] is connectable + formatZH: 检测远程数据库 [name][type] 连接性 + paramKeys: [] /databases/remote/del: post: consumes: diff --git a/frontend/src/api/modules/database.ts b/frontend/src/api/modules/database.ts index 30b2a6cf7..24a52813d 100644 --- a/frontend/src/api/modules/database.ts +++ b/frontend/src/api/modules/database.ts @@ -100,11 +100,14 @@ export const searchRemoteDBs = (params: Database.SearchRemoteDBPage) => { export const listRemoteDBs = (type: string) => { return http.get>(`/databases/remote/list/${type}`); }; +export const checkRemoteDB = (params: Database.RemoteDBCreate) => { + return http.post(`/databases/remote/check`, params, 40000); +}; export const addRemoteDB = (params: Database.RemoteDBCreate) => { - return http.post(`/databases/remote`, params); + return http.post(`/databases/remote`, params, 40000); }; export const editRemoteDB = (params: Database.RemoteDBUpdate) => { - return http.post(`/databases/remote/update`, params); + return http.post(`/databases/remote/update`, params, 40000); }; export const deleteRemoteDB = (id: number) => { return http.post(`/databases/remote/del`, { id: id }); diff --git a/frontend/src/views/database/mysql/remote/operate/index.vue b/frontend/src/views/database/mysql/remote/operate/index.vue index 16125c4dd..7a753c0d6 100644 --- a/frontend/src/views/database/mysql/remote/operate/index.vue +++ b/frontend/src/views/database/mysql/remote/operate/index.vue @@ -8,7 +8,7 @@ :back="handleClose" /> - + @@ -20,7 +20,7 @@ {{ dialogData.rowData!.name }} - + @@ -28,17 +28,23 @@ {{ $t('database.versionHelper') }} - + - + - + {{ $t('database.userHelper') }} - + @@ -49,7 +55,10 @@