mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-26 08:46:28 +08:00
feat: PHP runtime add php config (#8922)
This commit is contained in:
parent
470d7881cd
commit
8614e63b86
20 changed files with 411 additions and 77 deletions
|
|
@ -493,3 +493,45 @@ func (b *BaseApi) OperateSupervisorProcessFile(c *gin.Context) {
|
|||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Update PHP container config
|
||||
// @Accept json
|
||||
// @Param request body request.PHPContainerUpdate true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /runtimes/php/container/update [post]
|
||||
func (b *BaseApi) UpdatePHPContainer(c *gin.Context) {
|
||||
var req request.PHPContainerConfig
|
||||
if err := helper.CheckBindAndValidate(&req, c); err != nil {
|
||||
return
|
||||
}
|
||||
if err := runtimeService.UpdatePHPContainer(req); err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.Success(c)
|
||||
}
|
||||
|
||||
// @Tags Runtime
|
||||
// @Summary Get PHP container config
|
||||
// @Accept json
|
||||
// @Param id path integer true "request"
|
||||
// @Success 200 {object} response.PHPContainerConfig
|
||||
// @Security ApiKeyAuth
|
||||
// @Security Timestamp
|
||||
// @Router /runtimes/php/container/:id [get]
|
||||
func (b *BaseApi) GetPHPContainerConfig(c *gin.Context) {
|
||||
id, err := helper.GetParamID(c)
|
||||
if err != nil {
|
||||
helper.BadRequest(c, err)
|
||||
return
|
||||
}
|
||||
data, err := runtimeService.GetPHPContainerConfig(id)
|
||||
if err != nil {
|
||||
helper.InternalServer(c, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, data)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,3 +123,11 @@ type PHPSupervisorProcessFileReq struct {
|
|||
ID uint `json:"id" validate:"required"`
|
||||
SupervisorProcessFileReq
|
||||
}
|
||||
|
||||
type PHPContainerConfig struct {
|
||||
ID uint `json:"id" validate:"required"`
|
||||
ContainerName string `json:"containerName"`
|
||||
ExposedPorts []ExposedPort `json:"exposedPorts"`
|
||||
Environments []Environment `json:"environments"`
|
||||
Volumes []Volume `json:"volumes"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,11 +6,11 @@ type WebsiteAcmeAccount struct {
|
|||
URL string `gorm:"not null" json:"url"`
|
||||
PrivateKey string `gorm:"not null" json:"-"`
|
||||
Type string `gorm:"not null;default:letsencrypt" json:"type"`
|
||||
EabKid string `gorm:"default:null;" json:"eabKid"`
|
||||
EabHmacKey string `gorm:"default:null" json:"eabHmacKey"`
|
||||
EabKid string `json:"eabKid"`
|
||||
EabHmacKey string `json:"eabHmacKey"`
|
||||
KeyType string `gorm:"not null;default:2048" json:"keyType"`
|
||||
UseProxy bool `gorm:"default:false" json:"useProxy"`
|
||||
CaDirURL string `gorm:"default:null" json:"caDirURL"`
|
||||
CaDirURL string `json:"caDirURL"`
|
||||
}
|
||||
|
||||
func (w WebsiteAcmeAccount) TableName() string {
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ type IRuntimeService interface {
|
|||
GetPHPExtensions(runtimeID uint) (response.PHPExtensionRes, error)
|
||||
InstallPHPExtension(req request.PHPExtensionInstallReq) error
|
||||
UnInstallPHPExtension(req request.PHPExtensionInstallReq) error
|
||||
|
||||
GetPHPConfig(id uint) (*response.PHPConfig, error)
|
||||
UpdatePHPConfig(req request.PHPConfigUpdate) (err error)
|
||||
UpdatePHPConfigFile(req request.PHPFileUpdate) error
|
||||
|
|
@ -63,6 +64,9 @@ type IRuntimeService interface {
|
|||
UpdateFPMConfig(req request.FPMConfig) error
|
||||
GetFPMConfig(id uint) (*request.FPMConfig, error)
|
||||
|
||||
UpdatePHPContainer(req request.PHPContainerConfig) error
|
||||
GetPHPContainerConfig(id uint) (*request.PHPContainerConfig, error)
|
||||
|
||||
GetSupervisorProcess(id uint) ([]response.SupervisorProcessConfig, error)
|
||||
OperateSupervisorProcess(req request.PHPSupervisorProcessConfig) error
|
||||
OperateSupervisorProcessFile(req request.PHPSupervisorProcessFileReq) (string, error)
|
||||
|
|
@ -383,77 +387,9 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) {
|
|||
}
|
||||
res.AppParams = appParams
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet:
|
||||
res.Params = make(map[string]interface{})
|
||||
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||
if err != nil {
|
||||
if err := handleRuntimeDTO(&res, *runtime); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range envs {
|
||||
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
|
||||
if strings.Contains(k, "CONTAINER_PORT") {
|
||||
r := regexp.MustCompile(`_(\d+)$`)
|
||||
matches := r.FindStringSubmatch(k)
|
||||
containerPort, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
hostIP := envs[fmt.Sprintf("HOST_IP_%s", matches[1])]
|
||||
if hostIP == "" {
|
||||
hostIP = "0.0.0.0"
|
||||
}
|
||||
res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{
|
||||
ContainerPort: containerPort,
|
||||
HostPort: hostPort,
|
||||
HostIP: hostIP,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
res.Params[k] = v
|
||||
}
|
||||
}
|
||||
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
|
||||
res.Source = v
|
||||
}
|
||||
composeByte, err := files.NewFileOp().GetContent(runtime.GetComposePath())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res.Environments, err = getDockerComposeEnvironments(composeByte)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
volumes, err := getDockerComposeVolumes(composeByte)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defaultVolumes := make(map[string]string)
|
||||
switch runtime.Type {
|
||||
case constant.RuntimeNode:
|
||||
defaultVolumes = constant.RuntimeDefaultVolumes
|
||||
case constant.RuntimeJava:
|
||||
defaultVolumes = constant.RuntimeDefaultVolumes
|
||||
case constant.RuntimeGo:
|
||||
defaultVolumes = constant.GoDefaultVolumes
|
||||
case constant.RuntimePython:
|
||||
defaultVolumes = constant.RuntimeDefaultVolumes
|
||||
}
|
||||
for _, volume := range volumes {
|
||||
exist := false
|
||||
for key, value := range defaultVolumes {
|
||||
if key == volume.Source && value == volume.Target {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
res.Volumes = append(res.Volumes, volume)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return &res, nil
|
||||
|
|
@ -1080,6 +1016,100 @@ func (r *RuntimeService) GetFPMConfig(id uint) (*request.FPMConfig, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) UpdatePHPContainer(req request.PHPContainerConfig) error {
|
||||
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(req.ID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
hostPorts []string
|
||||
composeContent []byte
|
||||
)
|
||||
for _, export := range req.ExposedPorts {
|
||||
hostPorts = append(hostPorts, strconv.Itoa(export.HostPort))
|
||||
if err = checkRuntimePortExist(export.HostPort, false, runtime.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if req.ContainerName != "" && req.ContainerName != getRuntimeEnv(runtime.Env, "CONTAINER_NAME") {
|
||||
if err := checkContainerName(req.ContainerName); err != nil {
|
||||
return err
|
||||
}
|
||||
runtime.ContainerName = req.ContainerName
|
||||
}
|
||||
fileOp := files.NewFileOp()
|
||||
projectDir := path.Join(global.Dir.RuntimeDir, runtime.Type, runtime.Name)
|
||||
composeContent, err = fileOp.GetContent(path.Join(projectDir, "docker-compose.yml"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
envPath := path.Join(projectDir, ".env")
|
||||
if !fileOp.Stat(envPath) {
|
||||
_ = fileOp.CreateFile(envPath)
|
||||
}
|
||||
envs, err := gotenv.Read(envPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k := range envs {
|
||||
if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") || strings.HasPrefix(k, "HOST_IP_") || strings.Contains(k, "APP_PORT") {
|
||||
delete(envs, k)
|
||||
}
|
||||
}
|
||||
create := request.RuntimeCreate{
|
||||
Image: runtime.Image,
|
||||
Type: runtime.Type,
|
||||
Params: make(map[string]interface{}),
|
||||
NodeConfig: request.NodeConfig{
|
||||
ExposedPorts: req.ExposedPorts,
|
||||
Environments: req.Environments,
|
||||
Volumes: req.Volumes,
|
||||
},
|
||||
}
|
||||
composeContent, err = handleCompose(envs, composeContent, create, projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newMap := make(map[string]string)
|
||||
handleMap(create.Params, newMap)
|
||||
for k, v := range newMap {
|
||||
envs[k] = v
|
||||
}
|
||||
envStr, err := gotenv.Marshal(envs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err = gotenv.Write(envs, envPath); err != nil {
|
||||
return err
|
||||
}
|
||||
envContent := []byte(envStr)
|
||||
runtime.Env = string(envContent)
|
||||
runtime.DockerCompose = string(composeContent)
|
||||
runtime.Status = constant.StatusReCreating
|
||||
_ = runtimeRepo.Save(runtime)
|
||||
go reCreateRuntime(runtime)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) GetPHPContainerConfig(id uint) (*request.PHPContainerConfig, error) {
|
||||
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(id))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
runtimeDTO := response.NewRuntimeDTO(*runtime)
|
||||
if err := handleRuntimeDTO(&runtimeDTO, *runtime); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
res := &request.PHPContainerConfig{
|
||||
ID: runtime.ID,
|
||||
ContainerName: runtime.ContainerName,
|
||||
ExposedPorts: runtimeDTO.ExposedPorts,
|
||||
Environments: runtimeDTO.Environments,
|
||||
Volumes: runtimeDTO.Volumes,
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (r *RuntimeService) GetSupervisorProcess(id uint) ([]response.SupervisorProcessConfig, error) {
|
||||
runtime, err := runtimeRepo.GetFirst(context.Background(), repo.WithByID(id))
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import (
|
|||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
|
@ -564,7 +566,14 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
|
|||
create.Params[hostPortStr] = port.HostPort
|
||||
create.Params[hostIPStr] = port.HostIP
|
||||
}
|
||||
if create.Type == constant.RuntimePHP {
|
||||
ports = append(ports, fmt.Sprintf("127.0.0.1:${PANEL_APP_PORT_HTTP}:9000"))
|
||||
}
|
||||
serviceValue["ports"] = ports
|
||||
} else {
|
||||
if create.Type == constant.RuntimePHP {
|
||||
serviceValue["ports"] = []interface{}{fmt.Sprintf("127.0.0.1:${PANEL_APP_PORT_HTTP}:9000")}
|
||||
}
|
||||
}
|
||||
var environments []interface{}
|
||||
for _, e := range create.Environments {
|
||||
|
|
@ -581,6 +590,8 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime
|
|||
defaultVolumes = constant.RuntimeDefaultVolumes
|
||||
case constant.RuntimeGo:
|
||||
defaultVolumes = constant.GoDefaultVolumes
|
||||
case constant.RuntimePHP:
|
||||
defaultVolumes = constant.PHPDefaultVolumes
|
||||
}
|
||||
for k, v := range defaultVolumes {
|
||||
volumes = append(volumes, fmt.Sprintf("%s:%s", k, v))
|
||||
|
|
@ -875,3 +886,76 @@ func RestartPHPRuntime() {
|
|||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func handleRuntimeDTO(res *response.RuntimeDTO, runtime model.Runtime) error {
|
||||
res.Params = make(map[string]interface{})
|
||||
envs, err := gotenv.Unmarshal(runtime.Env)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for k, v := range envs {
|
||||
if strings.Contains(k, "CONTAINER_PORT") || strings.Contains(k, "HOST_PORT") {
|
||||
if strings.Contains(k, "CONTAINER_PORT") {
|
||||
r := regexp.MustCompile(`_(\d+)$`)
|
||||
matches := r.FindStringSubmatch(k)
|
||||
containerPort, err := strconv.Atoi(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hostPort, err := strconv.Atoi(envs[fmt.Sprintf("HOST_PORT_%s", matches[1])])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hostIP := envs[fmt.Sprintf("HOST_IP_%s", matches[1])]
|
||||
if hostIP == "" {
|
||||
hostIP = "0.0.0.0"
|
||||
}
|
||||
res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{
|
||||
ContainerPort: containerPort,
|
||||
HostPort: hostPort,
|
||||
HostIP: hostIP,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
res.Params[k] = v
|
||||
}
|
||||
}
|
||||
if v, ok := envs["CONTAINER_PACKAGE_URL"]; ok {
|
||||
res.Source = v
|
||||
}
|
||||
composeByte, err := files.NewFileOp().GetContent(runtime.GetComposePath())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
res.Environments, err = getDockerComposeEnvironments(composeByte)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
volumes, err := getDockerComposeVolumes(composeByte)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaultVolumes := make(map[string]string)
|
||||
switch runtime.Type {
|
||||
case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimePython, constant.RuntimeDotNet:
|
||||
defaultVolumes = constant.RuntimeDefaultVolumes
|
||||
case constant.RuntimeGo:
|
||||
defaultVolumes = constant.GoDefaultVolumes
|
||||
case constant.RuntimePHP:
|
||||
defaultVolumes = constant.PHPDefaultVolumes
|
||||
}
|
||||
for _, volume := range volumes {
|
||||
exist := false
|
||||
for key, value := range defaultVolumes {
|
||||
if key == volume.Source && value == volume.Target {
|
||||
exist = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
res.Volumes = append(res.Volumes, volume)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,3 +38,17 @@ var RuntimeDefaultVolumes = map[string]string{
|
|||
"./run.sh": "/run.sh",
|
||||
"./.env": "/.env",
|
||||
}
|
||||
|
||||
var PHPDefaultVolumes = map[string]string{
|
||||
"${PANEL_WEBSITE_DIR}": "/www/",
|
||||
"./conf": "/usr/local/etc/php",
|
||||
"./conf/conf.d": "/usr/local/etc/php/conf.d",
|
||||
"./conf/php-fpm.conf": "/usr/local/etc/php-fpm.d/www.conf",
|
||||
"./log": "/var/log/php",
|
||||
"./extensions": "${EXTENSION_DIR}",
|
||||
"./supervisor/supervisord.conf": "/etc/supervisord.conf",
|
||||
"./supervisor/supervisor.d/php-fpm.ini": "/etc/supervisor.d/php-fpm.ini",
|
||||
"./supervisor/supervisor.d": "/etc/supervisor.d",
|
||||
"./supervisor/log": "/var/log/supervisor",
|
||||
"./composer": "/tmp/composer",
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ func (r *RuntimeRouter) InitRouter(Router *gin.RouterGroup) {
|
|||
groupRouter.POST("/php/fpm/config", baseApi.UpdateFPMConfig)
|
||||
groupRouter.GET("/php/fpm/config/:id", baseApi.GetFPMConfig)
|
||||
|
||||
groupRouter.POST("/php/container/update", baseApi.UpdatePHPContainer)
|
||||
groupRouter.GET("/php/container/:id", baseApi.GetPHPContainerConfig)
|
||||
|
||||
groupRouter.GET("/supervisor/process/:id", baseApi.GetSupervisorProcess)
|
||||
groupRouter.POST("/supervisor/process", baseApi.OperateSupervisorProcess)
|
||||
groupRouter.POST("/supervisor/process/file", baseApi.OperateSupervisorProcessFile)
|
||||
|
|
|
|||
|
|
@ -210,4 +210,12 @@ export namespace Runtime {
|
|||
numprocs: string;
|
||||
id: number;
|
||||
}
|
||||
|
||||
export interface PHPContainerConfig {
|
||||
id: number;
|
||||
containerName: string;
|
||||
exposedPorts: ExposedPort[];
|
||||
environments: Environment[];
|
||||
volumes: Volume[];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,3 +121,11 @@ export const operateSupervisorProcessFile = (req: Runtime.ProcessFileReq) => {
|
|||
export const createSupervisorProcess = (req: Runtime.SupersivorProcess) => {
|
||||
return http.post(`/runtimes/supervisor/process`, req);
|
||||
};
|
||||
|
||||
export const getPHPContainerConfig = (id: number) => {
|
||||
return http.get<Runtime.PHPContainerConfig>(`/runtimes/php/container/${id}`);
|
||||
};
|
||||
|
||||
export const updatePHPContainerConfig = (req: Runtime.PHPContainerConfig) => {
|
||||
return http.post<any>(`/runtimes/php/container/update`, req);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2506,6 +2506,9 @@ const message = {
|
|||
extension: 'Extension',
|
||||
extensionHelper: 'Please use multiple extensions, split',
|
||||
toExtensionsList: 'View extension list',
|
||||
containerConfig: 'Container Configuration',
|
||||
containerConfigHelper:
|
||||
'Environment variables and other information can be modified in Configuration - Container Configuration after creation',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: 'The hash table size of the server name',
|
||||
|
|
|
|||
|
|
@ -2412,6 +2412,8 @@ const message = {
|
|||
extension: '拡大',
|
||||
extensionHelper: '複数の拡張機能を使用して、分割してください',
|
||||
toExtensionsList: '拡張リストを表示します',
|
||||
containerConfig: 'コンテナ設定',
|
||||
containerConfigHelper: '環境変数などの情報は、作成完了後に設定 - コンテナ設定で変更できます',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: 'サーバー名のハッシュテーブルサイズ',
|
||||
|
|
|
|||
|
|
@ -2370,6 +2370,8 @@ const message = {
|
|||
extension: '확장',
|
||||
extensionHelper: '여러 확장은 쉼표로 구분하여 입력하세요.',
|
||||
toExtensionsList: '확장 목록 보기',
|
||||
containerConfig: '컨테이너 구성',
|
||||
containerConfigHelper: '환경 변수 및 기타 정보는 생성 후 구성 - 컨테이너 구성에서 수정할 수 있습니다',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: '서버 이름의 해시 테이블 크기',
|
||||
|
|
|
|||
|
|
@ -2467,6 +2467,9 @@ const message = {
|
|||
extension: 'Sambungan',
|
||||
extensionHelper: 'Gunakan pemisah untuk banyak sambungan',
|
||||
toExtensionsList: 'Lihat senarai sambungan',
|
||||
containerConfig: 'Konfigurasi Bekas',
|
||||
containerConfigHelper:
|
||||
'Pembolehubah persekitaran dan maklumat lain boleh diubah suai dalam Konfigurasi - Konfigurasi Bekas selepas penciptaan',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: 'Saiz jadual hash nama pelayan',
|
||||
|
|
|
|||
|
|
@ -2464,6 +2464,9 @@ const message = {
|
|||
extension: 'Extensão',
|
||||
extensionHelper: 'Para múltiplas extensões, separe com vírgulas',
|
||||
toExtensionsList: 'Ver lista de extensões',
|
||||
containerConfig: 'Configuração do Contêiner',
|
||||
containerConfigHelper:
|
||||
'Variáveis de ambiente e outras informações podem ser modificadas em Configuração - Configuração do Contêiner após a criação',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: 'The hash table size of the server name',
|
||||
|
|
|
|||
|
|
@ -2462,6 +2462,9 @@ const message = {
|
|||
extension: 'Расширение',
|
||||
extensionHelper: 'Используйте несколько расширений, разделяйте запятыми',
|
||||
toExtensionsList: 'Просмотр списка расширений',
|
||||
containerConfig: 'Конфигурация контейнера',
|
||||
containerConfigHelper:
|
||||
'Переменные окружения и другие данные можно изменить в разделе Конфигурация - Конфигурация контейнера после создания',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: 'Размер хэш-таблицы для имен серверов',
|
||||
|
|
|
|||
|
|
@ -2324,6 +2324,8 @@ const message = {
|
|||
extension: '擴充',
|
||||
extensionHelper: '多個擴充功能,分割',
|
||||
toExtensionsList: '檢視擴充清單',
|
||||
containerConfig: '容器配置',
|
||||
containerConfigHelper: '環境變量等信息可以在創建完成之後在配置-容器配置中修改',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: '服務器名字的hash表大小',
|
||||
|
|
|
|||
|
|
@ -2314,6 +2314,8 @@ const message = {
|
|||
extension: '扩展',
|
||||
extensionsHelper: '多个扩展请用,分割',
|
||||
toExtensionsList: '查看扩展列表',
|
||||
containerConfig: '容器配置',
|
||||
containerConfigHelper: '环境变量等信息可以在创建完成之后在配置-容器配置中修改',
|
||||
},
|
||||
nginx: {
|
||||
serverNamesHashBucketSizeHelper: '服务器名字的hash表大小',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,115 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-row v-loading="loading">
|
||||
<el-col :span="22" :offset="1">
|
||||
<el-form
|
||||
v-loading="loading"
|
||||
ref="runtimeForm"
|
||||
label-position="top"
|
||||
:model="containerConfig"
|
||||
:rules="rules"
|
||||
label-width="125px"
|
||||
:validate-on-rule-change="false"
|
||||
>
|
||||
<el-form-item :label="$t('app.containerName')" prop="containerName">
|
||||
<el-input v-model.trim="containerConfig.containerName"></el-input>
|
||||
</el-form-item>
|
||||
<el-tabs type="border-card">
|
||||
<el-tab-pane :label="$t('commons.table.port')">
|
||||
<PortConfig v-model="containerConfig" :mode="'edit'" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('runtime.environment')">
|
||||
<Environment :environments="containerConfig.environments" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('container.mount')">
|
||||
<Volumes :volumes="containerConfig.volumes" />
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<el-form-item class="mt-2">
|
||||
<el-button type="primary" @click="onSaveStart(runtimeForm)">
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import { getPHPContainerConfig, updatePHPContainerConfig } from '@/api/modules/runtime';
|
||||
import { FormInstance } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import PortConfig from '@/views/website/runtime/port/index.vue';
|
||||
import Environment from '@/views/website/runtime/environment/index.vue';
|
||||
import Volumes from '@/views/website/runtime/volume/index.vue';
|
||||
import i18n from '@/lang';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
|
||||
const props = defineProps<{
|
||||
id: number;
|
||||
}>();
|
||||
const loading = ref<boolean>(false);
|
||||
const runtimeForm = ref<FormInstance>();
|
||||
const containerConfig = ref<Runtime.PHPContainerConfig>({
|
||||
id: 0,
|
||||
containerName: '',
|
||||
exposedPorts: [],
|
||||
environments: [],
|
||||
volumes: [],
|
||||
});
|
||||
|
||||
const rules = {
|
||||
containerName: [Rules.containerName, Rules.requiredInput],
|
||||
};
|
||||
|
||||
const getConfig = async () => {
|
||||
const res = await getPHPContainerConfig(props.id);
|
||||
containerConfig.value.exposedPorts = res.data.exposedPorts || [];
|
||||
containerConfig.value.environments = res.data.environments || [];
|
||||
containerConfig.value.volumes = res.data.volumes || [];
|
||||
containerConfig.value.containerName = res.data.containerName || '';
|
||||
};
|
||||
|
||||
const onSaveStart = async (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
const action = await ElMessageBox.confirm(
|
||||
i18n.global.t('runtime.phpConfigHelper'),
|
||||
i18n.global.t('database.confChange'),
|
||||
{
|
||||
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||
type: 'info',
|
||||
},
|
||||
);
|
||||
if (action === 'confirm') {
|
||||
loading.value = true;
|
||||
submit();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
try {
|
||||
await updatePHPContainerConfig({
|
||||
id: props.id,
|
||||
containerName: containerConfig.value.containerName,
|
||||
exposedPorts: containerConfig.value.exposedPorts,
|
||||
environments: containerConfig.value.environments,
|
||||
volumes: containerConfig.value.volumes,
|
||||
});
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
} catch (error) {
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getConfig();
|
||||
});
|
||||
</script>
|
||||
|
|
@ -26,6 +26,9 @@
|
|||
<el-tab-pane :label="'FPM ' + $t('website.source')" name="3">
|
||||
<PHP :id="runtime.id" v-if="index == '3'" :type="'fpm'"></PHP>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('php.containerConfig')" name="6">
|
||||
<Container :id="runtime.id" v-if="index == '6'"></Container>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
|
|
@ -39,6 +42,7 @@ import Function from './function/index.vue';
|
|||
import Upload from './upload/index.vue';
|
||||
import PHP from './php-fpm/index.vue';
|
||||
import Performance from './performance/index.vue';
|
||||
import Container from './container/index.vue';
|
||||
|
||||
const index = ref('0');
|
||||
const open = ref(false);
|
||||
|
|
|
|||
|
|
@ -119,10 +119,9 @@
|
|||
<el-form-item :label="$t('app.containerName')" prop="params.CONTAINER_NAME">
|
||||
<el-input v-model.trim="runtime.params['CONTAINER_NAME']"></el-input>
|
||||
</el-form-item>
|
||||
<el-text>{{ $t('container.env') }}</el-text>
|
||||
<br />
|
||||
<Environment :environments="runtime.environments" />
|
||||
<br />
|
||||
<el-form-item>
|
||||
<el-alert :title="$t('php.containerConfigHelper')" type="info" :closable="false" />
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-alert type="warning" :closable="false">
|
||||
<template #default>
|
||||
|
|
@ -186,7 +185,6 @@
|
|||
<script lang="ts" setup>
|
||||
import { App } from '@/api/interface/app';
|
||||
import { Runtime } from '@/api/interface/runtime';
|
||||
import Environment from '@/views/website/runtime/environment/index.vue';
|
||||
import { getAppByKey, getAppDetail, searchApp } from '@/api/modules/app';
|
||||
import { CreateRuntime, GetRuntime, ListPHPExtensions, UpdateRuntime } from '@/api/modules/runtime';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue