mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-12 08:26:50 +08:00
feat: 完成数据库端口修改功能
This commit is contained in:
parent
85419b6dd4
commit
8431f49c47
14 changed files with 152 additions and 11 deletions
|
@ -1,11 +1,13 @@
|
||||||
package v1
|
package v1
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/global"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"strconv"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (b *BaseApi) SearchApp(c *gin.Context) {
|
func (b *BaseApi) SearchApp(c *gin.Context) {
|
||||||
|
@ -180,3 +182,22 @@ func (b *BaseApi) GetUpdateVersions(c *gin.Context) {
|
||||||
|
|
||||||
helper.SuccessWithData(c, versions)
|
helper.SuccessWithData(c, versions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *BaseApi) ChangeAppPort(c *gin.Context) {
|
||||||
|
var req dto.PortUpdate
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := appService.ChangeAppPort(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
helper.SuccessWithData(c, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -78,6 +79,12 @@ type AppInstallOperate struct {
|
||||||
Operate AppOperate `json:"operate" validate:"required"`
|
Operate AppOperate `json:"operate" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type PortUpdate struct {
|
||||||
|
Key string `json:"key"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Port int64 `json:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
type AppService struct {
|
type AppService struct {
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
|
|
|
@ -151,6 +151,7 @@ type RedisConfUpdateByFile struct {
|
||||||
|
|
||||||
type RedisConf struct {
|
type RedisConf struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
|
Port int64 `json:"port"`
|
||||||
ContainerName string `json:"containerName"`
|
ContainerName string `json:"containerName"`
|
||||||
Timeout string `json:"timeout"`
|
Timeout string `json:"timeout"`
|
||||||
Maxclients string `json:"maxclients"`
|
Maxclients string `json:"maxclients"`
|
||||||
|
|
|
@ -22,7 +22,7 @@ type IMysqlRepo interface {
|
||||||
LoadRunningVersion(keys []string) ([]string, error)
|
LoadRunningVersion(keys []string) ([]string, error)
|
||||||
LoadBaseInfoByName(name string) (*RootInfo, error)
|
LoadBaseInfoByName(name string) (*RootInfo, error)
|
||||||
LoadRedisBaseInfo() (*RootInfo, error)
|
LoadRedisBaseInfo() (*RootInfo, error)
|
||||||
UpdateDatabasePassword(id uint, vars map[string]interface{}) error
|
UpdateDatabaseInfo(id uint, vars map[string]interface{}) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIMysqlRepo() IMysqlRepo {
|
func NewIMysqlRepo() IMysqlRepo {
|
||||||
|
@ -181,7 +181,7 @@ func (u *MysqlRepo) Update(id uint, vars map[string]interface{}) error {
|
||||||
return global.DB.Model(&model.DatabaseMysql{}).Where("id = ?", id).Updates(vars).Error
|
return global.DB.Model(&model.DatabaseMysql{}).Where("id = ?", id).Updates(vars).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *MysqlRepo) UpdateDatabasePassword(id uint, vars map[string]interface{}) error {
|
func (u *MysqlRepo) UpdateDatabaseInfo(id uint, vars map[string]interface{}) error {
|
||||||
if err := global.DB.Model(&model.AppInstall{}).Where("id = ?", id).Updates(vars).Error; err != nil {
|
if err := global.DB.Model(&model.AppInstall{}).Where("id = ?", id).Updates(vars).Error; err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||||
|
@ -16,9 +22,6 @@ import (
|
||||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"os"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type AppService struct {
|
type AppService struct {
|
||||||
|
@ -197,6 +200,58 @@ func (a AppService) OperateInstall(req dto.AppInstallOperate) error {
|
||||||
return appInstallRepo.Save(&install)
|
return appInstallRepo.Save(&install)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a AppService) ChangeAppPort(req dto.PortUpdate) error {
|
||||||
|
var (
|
||||||
|
files []string
|
||||||
|
newFiles []string
|
||||||
|
)
|
||||||
|
app, err := mysqlRepo.LoadBaseInfoByName(req.Name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ComposeDir := fmt.Sprintf("%s/%s/%s", constant.AppInstallDir, req.Key, req.Name)
|
||||||
|
ComposeFile := fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, req.Key, req.Name)
|
||||||
|
path := fmt.Sprintf("%s/.env", ComposeDir)
|
||||||
|
lineBytes, err := ioutil.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
files = strings.Split(string(lineBytes), "\n")
|
||||||
|
}
|
||||||
|
for _, line := range files {
|
||||||
|
if strings.HasPrefix(line, "PANEL_APP_PORT_HTTP=") {
|
||||||
|
newFiles = append(newFiles, fmt.Sprintf("PANEL_APP_PORT_HTTP=%v", req.Port))
|
||||||
|
} else {
|
||||||
|
newFiles = append(newFiles, line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
file, err := os.OpenFile(path, os.O_WRONLY, 0666)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
_, err = file.WriteString(strings.Join(newFiles, "\n"))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := mysqlRepo.UpdateDatabaseInfo(app.ID, map[string]interface{}{
|
||||||
|
"env": strings.ReplaceAll(app.Env, strconv.FormatInt(app.Port, 10), strconv.FormatInt(req.Port, 10)),
|
||||||
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
stdout, err := compose.Down(ComposeFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(stdout)
|
||||||
|
}
|
||||||
|
stdout, err = compose.Up(ComposeFile)
|
||||||
|
if err != nil {
|
||||||
|
return errors.New(stdout)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) error {
|
func (a AppService) Install(name string, appDetailId uint, params map[string]interface{}) error {
|
||||||
|
|
||||||
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", params)
|
httpPort, err := checkPort("PANEL_APP_PORT_HTTP", params)
|
||||||
|
|
|
@ -224,7 +224,7 @@ func (u *MysqlService) ChangeInfo(info dto.ChangeDBInfo) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ = mysqlRepo.UpdateDatabasePassword(app.ID, map[string]interface{}{
|
_ = mysqlRepo.UpdateDatabaseInfo(app.ID, map[string]interface{}{
|
||||||
"param": strings.ReplaceAll(app.Param, app.Password, info.Value),
|
"param": strings.ReplaceAll(app.Param, app.Password, info.Value),
|
||||||
"env": strings.ReplaceAll(app.Env, app.Password, info.Value),
|
"env": strings.ReplaceAll(app.Env, app.Password, info.Value),
|
||||||
})
|
})
|
||||||
|
|
|
@ -47,7 +47,7 @@ func (u *RedisService) UpdateConf(req dto.RedisConfUpdate) error {
|
||||||
if err := configSetStr(redisInfo.ContainerName, redisInfo.Password, "maxclients", req.Maxclients); err != nil {
|
if err := configSetStr(redisInfo.ContainerName, redisInfo.Password, "maxclients", req.Maxclients); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := mysqlRepo.UpdateDatabasePassword(redisInfo.ID, map[string]interface{}{
|
if err := mysqlRepo.UpdateDatabaseInfo(redisInfo.ID, map[string]interface{}{
|
||||||
"param": strings.ReplaceAll(redisInfo.Param, redisInfo.Password, req.Requirepass),
|
"param": strings.ReplaceAll(redisInfo.Param, redisInfo.Password, req.Requirepass),
|
||||||
"env": strings.ReplaceAll(redisInfo.Env, redisInfo.Password, req.Requirepass),
|
"env": strings.ReplaceAll(redisInfo.Env, redisInfo.Password, req.Requirepass),
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
|
@ -133,6 +133,7 @@ func (u *RedisService) LoadConf() (*dto.RedisConf, error) {
|
||||||
var item dto.RedisConf
|
var item dto.RedisConf
|
||||||
item.ContainerName = redisInfo.ContainerName
|
item.ContainerName = redisInfo.ContainerName
|
||||||
item.Name = redisInfo.Name
|
item.Name = redisInfo.Name
|
||||||
|
item.Port = redisInfo.Port
|
||||||
if item.Timeout, err = configGetStr(redisInfo.ContainerName, redisInfo.Password, "timeout"); err != nil {
|
if item.Timeout, err = configGetStr(redisInfo.ContainerName, redisInfo.Password, "timeout"); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
|
||||||
appRouter.POST("/installed/sync", baseApi.SyncInstalled)
|
appRouter.POST("/installed/sync", baseApi.SyncInstalled)
|
||||||
appRouter.POST("/installed/backups", baseApi.SearchInstalledBackup)
|
appRouter.POST("/installed/backups", baseApi.SearchInstalledBackup)
|
||||||
appRouter.POST("/installed/backups/del", baseApi.DeleteAppBackup)
|
appRouter.POST("/installed/backups/del", baseApi.DeleteAppBackup)
|
||||||
|
appRouter.POST("/installed/port/change", baseApi.ChangeAppPort)
|
||||||
appRouter.GET("/services/:key", baseApi.GetServices)
|
appRouter.GET("/services/:key", baseApi.GetServices)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,12 @@ export namespace App {
|
||||||
params: any;
|
params: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ChangePort {
|
||||||
|
key: string;
|
||||||
|
name: string;
|
||||||
|
port: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AppInstalled extends CommonModel {
|
export interface AppInstalled extends CommonModel {
|
||||||
name: string;
|
name: string;
|
||||||
appId: string;
|
appId: string;
|
||||||
|
|
|
@ -150,6 +150,7 @@ export namespace Database {
|
||||||
}
|
}
|
||||||
export interface RedisConf {
|
export interface RedisConf {
|
||||||
name: string;
|
name: string;
|
||||||
|
port: number;
|
||||||
timeout: number;
|
timeout: number;
|
||||||
maxclients: number;
|
maxclients: number;
|
||||||
requirepass: string;
|
requirepass: string;
|
||||||
|
|
|
@ -22,6 +22,10 @@ export const InstallApp = (install: App.AppInstall) => {
|
||||||
return http.post<any>('apps/install', install);
|
return http.post<any>('apps/install', install);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ChangePort = (params: App.ChangePort) => {
|
||||||
|
return http.post<any>('apps/installed/port/change', params);
|
||||||
|
};
|
||||||
|
|
||||||
export const GetAppInstalled = (info: ReqPage) => {
|
export const GetAppInstalled = (info: ReqPage) => {
|
||||||
return http.post<ResPage<App.AppInstalled>>('apps/installed', info);
|
return http.post<ResPage<App.AppInstalled>>('apps/installed', info);
|
||||||
};
|
};
|
||||||
|
|
|
@ -171,6 +171,7 @@ export default {
|
||||||
baseSetting: '基础设置',
|
baseSetting: '基础设置',
|
||||||
remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险,开启需谨慎!',
|
remoteConnHelper: 'root 帐号远程连接 mysql 有安全风险,开启需谨慎!',
|
||||||
confChange: '配置修改',
|
confChange: '配置修改',
|
||||||
|
portHelper: '该端口为容器对外暴露端口,修改需要单独保存并且重启容器!',
|
||||||
|
|
||||||
currentStatus: '当前状态',
|
currentStatus: '当前状态',
|
||||||
runTime: '启动时间',
|
runTime: '启动时间',
|
||||||
|
|
|
@ -104,6 +104,7 @@ import {
|
||||||
updateMysqlConfByFile,
|
updateMysqlConfByFile,
|
||||||
updateMysqlDBInfo,
|
updateMysqlDBInfo,
|
||||||
} from '@/api/modules/database';
|
} from '@/api/modules/database';
|
||||||
|
import { ChangePort } from '@/api/modules/app';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
|
|
||||||
|
@ -152,6 +153,16 @@ const onSave = async (formEl: FormInstance | undefined, key: string, val: any) =
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (key === 'port') {
|
||||||
|
let params = {
|
||||||
|
key: baseInfo.mysqlKey,
|
||||||
|
name: mysqlName.value,
|
||||||
|
port: val,
|
||||||
|
};
|
||||||
|
await ChangePort(params);
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
let changeForm = {
|
let changeForm = {
|
||||||
id: 0,
|
id: 0,
|
||||||
mysqlName: mysqlName.value,
|
mysqlName: mysqlName.value,
|
||||||
|
|
|
@ -9,8 +9,15 @@
|
||||||
<el-row style="margin-top: 20px">
|
<el-row style="margin-top: 20px">
|
||||||
<el-col :span="1"><br /></el-col>
|
<el-col :span="1"><br /></el-col>
|
||||||
<el-col :span="10">
|
<el-col :span="10">
|
||||||
<el-form-item :label="$t('setting.port')" prop="port">
|
<el-form-item :label="$t('setting.port')" prop="port" :rules="Rules.port">
|
||||||
<el-input clearable type="number" v-model.number="form.port" />
|
<el-input clearable type="number" v-model.number="form.port">
|
||||||
|
<template #append>
|
||||||
|
<el-button @click="onChangePort(formRef)" icon="Collection">
|
||||||
|
{{ $t('commons.button.save') }}
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<span class="input-help">{{ $t('database.portHelper') }}</span>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item :label="$t('setting.password')" prop="requirepass">
|
<el-form-item :label="$t('setting.password')" prop="requirepass">
|
||||||
<el-input type="password" show-password clearable v-model="form.requirepass" />
|
<el-input type="password" show-password clearable v-model="form.requirepass" />
|
||||||
|
@ -71,6 +78,7 @@ import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||||
import { loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/modules/database';
|
import { loadRedisConf, updateRedisConf, updateRedisConfByFile } from '@/api/modules/database';
|
||||||
import i18n from '@/lang';
|
import i18n from '@/lang';
|
||||||
import { Rules } from '@/global/form-rules';
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import { ChangePort } from '@/api/modules/app';
|
||||||
|
|
||||||
const extensions = [javascript(), oneDark];
|
const extensions = [javascript(), oneDark];
|
||||||
const confShowType = ref('base');
|
const confShowType = ref('base');
|
||||||
|
@ -78,7 +86,7 @@ const confShowType = ref('base');
|
||||||
const restartNow = ref(false);
|
const restartNow = ref(false);
|
||||||
const form = reactive({
|
const form = reactive({
|
||||||
name: '',
|
name: '',
|
||||||
port: 3306,
|
port: 6379,
|
||||||
requirepass: '',
|
requirepass: '',
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
maxclients: 0,
|
maxclients: 0,
|
||||||
|
@ -105,6 +113,29 @@ const onClose = (): void => {
|
||||||
settingShow.value = false;
|
settingShow.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onChangePort = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
const result = await formEl.validateField('port', callback);
|
||||||
|
if (!result) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let params = {
|
||||||
|
key: 'redis',
|
||||||
|
name: form.name,
|
||||||
|
port: form.port,
|
||||||
|
};
|
||||||
|
await ChangePort(params);
|
||||||
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
function callback(error: any) {
|
||||||
|
if (error) {
|
||||||
|
return error.message;
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const onSave = async (formEl: FormInstance | undefined) => {
|
const onSave = async (formEl: FormInstance | undefined) => {
|
||||||
if (confShowType.value === 'all') {
|
if (confShowType.value === 'all') {
|
||||||
onSaveFile();
|
onSaveFile();
|
||||||
|
@ -149,6 +180,7 @@ const loadform = async () => {
|
||||||
form.maxclients = Number(res.data?.maxclients);
|
form.maxclients = Number(res.data?.maxclients);
|
||||||
form.requirepass = res.data?.requirepass;
|
form.requirepass = res.data?.requirepass;
|
||||||
form.maxmemory = Number(res.data?.maxmemory);
|
form.maxmemory = Number(res.data?.maxmemory);
|
||||||
|
form.port = Number(res.data?.port);
|
||||||
loadMysqlConf(`/opt/1Panel/data/apps/redis/${form.name}/conf/redis.conf`);
|
loadMysqlConf(`/opt/1Panel/data/apps/redis/${form.name}/conf/redis.conf`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue