From edf24dbc49c9d4c1ed259a683892ccbe30aa90d2 Mon Sep 17 00:00:00 2001 From: zhengkunwang <31820853+zhengkunwang223@users.noreply.github.com> Date: Sun, 26 Jan 2025 22:29:20 +0800 Subject: [PATCH] feat: Runtime environment supports running without port configuration (#7775) --- agent/app/dto/request/runtime.go | 5 +- agent/app/dto/response/runtime.go | 2 +- agent/app/model/runtime.go | 2 +- agent/app/repo/common.go | 6 ++ agent/app/repo/runtime.go | 5 +- agent/app/service/runtime.go | 72 ++++++-------- agent/app/service/runtime_utils.go | 44 ++++++++- agent/cmd/server/conf/app.yaml | 2 +- frontend/src/api/interface/runtime.ts | 1 + frontend/src/components/drawer-pro/index.vue | 2 +- .../src/views/app-store/setting/index.vue | 3 - .../views/website/runtime/dotnet/index.vue | 8 +- .../website/runtime/dotnet/operate/index.vue | 2 - .../website/runtime/environment/index.vue | 4 +- .../src/views/website/runtime/go/index.vue | 8 +- .../website/runtime/go/operate/index.vue | 2 - .../src/views/website/runtime/java/index.vue | 8 +- .../website/runtime/java/operate/index.vue | 2 - .../src/views/website/runtime/node/index.vue | 8 +- .../website/runtime/node/operate/index.vue | 2 - .../src/views/website/runtime/port/index.vue | 94 ++++++++----------- .../views/website/runtime/python/index.vue | 8 +- .../website/runtime/python/operate/index.vue | 2 - .../views/website/runtime/volume/index.vue | 4 +- .../views/website/website/create/index.vue | 10 +- frontend/src/views/website/website/index.vue | 11 ++- 26 files changed, 171 insertions(+), 146 deletions(-) diff --git a/agent/app/dto/request/runtime.go b/agent/app/dto/request/runtime.go index f8e1e6174..d7444f40c 100644 --- a/agent/app/dto/request/runtime.go +++ b/agent/app/dto/request/runtime.go @@ -42,8 +42,9 @@ type Volume struct { } type ExposedPort struct { - HostPort int `json:"hostPort"` - ContainerPort int `json:"containerPort"` + HostPort int `json:"hostPort"` + ContainerPort int `json:"containerPort"` + HostIP string `json:"hostIP"` } type RuntimeDelete struct { diff --git a/agent/app/dto/response/runtime.go b/agent/app/dto/response/runtime.go index 16a9de36d..1338a2690 100644 --- a/agent/app/dto/response/runtime.go +++ b/agent/app/dto/response/runtime.go @@ -23,7 +23,7 @@ type RuntimeDTO struct { CreatedAt time.Time `json:"createdAt"` CodeDir string `json:"codeDir"` AppParams []AppParam `json:"appParams"` - Port int `json:"port"` + Port string `json:"port"` Path string `json:"path"` ExposedPorts []request.ExposedPort `json:"exposedPorts"` Environments []request.Environment `json:"environments"` diff --git a/agent/app/model/runtime.go b/agent/app/model/runtime.go index 9b4598d7e..9824f1bc1 100644 --- a/agent/app/model/runtime.go +++ b/agent/app/model/runtime.go @@ -19,7 +19,7 @@ type Runtime struct { Type string `gorm:"not null" json:"type"` Status string `gorm:"not null" json:"status"` Resource string `gorm:"not null" json:"resource"` - Port int `json:"port"` + Port string `json:"port"` Message string `json:"message"` CodeDir string `json:"codeDir"` ContainerName string `json:"containerName"` diff --git a/agent/app/repo/common.go b/agent/app/repo/common.go index 2a9127926..fadd2fd8d 100644 --- a/agent/app/repo/common.go +++ b/agent/app/repo/common.go @@ -18,6 +18,12 @@ func WithByID(id uint) DBOption { } } +func WithByNOTID(id uint) DBOption { + return func(g *gorm.DB) *gorm.DB { + return g.Where("id != ?", id) + } +} + func WithByIDs(ids []uint) DBOption { return func(g *gorm.DB) *gorm.DB { return g.Where("id in (?)", ids) diff --git a/agent/app/repo/runtime.go b/agent/app/repo/runtime.go index 01b700176..0cfe48cae 100644 --- a/agent/app/repo/runtime.go +++ b/agent/app/repo/runtime.go @@ -2,6 +2,7 @@ package repo import ( "context" + "fmt" "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/global" @@ -55,7 +56,9 @@ func (r *RuntimeRepo) WithNotId(id uint) DBOption { func (r *RuntimeRepo) WithPort(port int) DBOption { return func(g *gorm.DB) *gorm.DB { - return g.Where("port = ?", port) + portStr := fmt.Sprintf("%d", port) + regexPattern := fmt.Sprintf("(^|,)%s(,|$)", portStr) + return g.Where("port REGEXP ?", regexPattern) } } diff --git a/agent/app/service/runtime.go b/agent/app/service/runtime.go index d65d1989a..d40b3601e 100644 --- a/agent/app/service/runtime.go +++ b/agent/app/service/runtime.go @@ -93,7 +93,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e return nil, err } } - + var hostPorts []string switch create.Type { case constant.RuntimePHP: if create.Resource == constant.ResourceLocal { @@ -116,17 +116,12 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e } create.Install = true for _, export := range create.ExposedPorts { + hostPorts = append(hostPorts, strconv.Itoa(export.HostPort)) if err := checkPortExist(export.HostPort); err != nil { return nil, err } } } - portValue, _ := create.Params["PANEL_APP_PORT_HTTP"] - if portValue != nil { - if err := checkPortExist(int(portValue.(float64))); err != nil { - return nil, err - } - } containerName, ok := create.Params["CONTAINER_NAME"] if !ok { return nil, buserr.New("ErrContainerNameIsNull") @@ -159,7 +154,7 @@ func (r *RuntimeService) Create(create request.RuntimeCreate) (*model.Runtime, e Resource: create.Resource, Version: create.Version, ContainerName: containerName.(string), - Port: int(portValue.(float64)), + Port: strings.Join(hostPorts, ","), } switch create.Type { @@ -352,34 +347,30 @@ func (r *RuntimeService) Get(id uint) (*response.RuntimeDTO, error) { return nil, err } for k, v := range envs { - switch k { - case "APP_PORT", "PANEL_APP_PORT_HTTP": - port, err := strconv.Atoi(v) - if err != nil { - return nil, err - } - res.Params[k] = port - default: - 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 - } - res.ExposedPorts = append(res.ExposedPorts, request.ExposedPort{ - ContainerPort: containerPort, - HostPort: hostPort, - }) + 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 } - } else { - res.Params[k] = v + 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 { @@ -437,7 +428,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error { } oldImage := runtime.Image oldEnv := runtime.Env - port := int(req.Params["PANEL_APP_PORT_HTTP"].(float64)) + var hostPorts []string switch runtime.Type { case constant.RuntimePHP: exist, _ := runtimeRepo.GetFirst(runtimeRepo.WithImage(req.Name), runtimeRepo.WithNotId(req.ID)) @@ -445,14 +436,9 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error { return buserr.New("ErrImageExist") } case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet: - if runtime.Port != port { - if err = checkPortExist(port); err != nil { - return err - } - runtime.Port = port - } for _, export := range req.ExposedPorts { - if err = checkPortExist(export.HostPort); err != nil { + hostPorts = append(hostPorts, strconv.Itoa(export.HostPort)) + if err = checkRuntimePortExist(export.HostPort, false, runtime.ID); err != nil { return err } } @@ -522,7 +508,7 @@ func (r *RuntimeService) Update(req request.RuntimeUpdate) error { case constant.RuntimeNode, constant.RuntimeJava, constant.RuntimeGo, constant.RuntimePython, constant.RuntimeDotNet: runtime.Version = req.Version runtime.CodeDir = req.CodeDir - runtime.Port = port + runtime.Port = strings.Join(hostPorts, ",") runtime.Status = constant.RuntimeReCreating _ = runtimeRepo.Save(runtime) go reCreateRuntime(runtime) diff --git a/agent/app/service/runtime_utils.go b/agent/app/service/runtime_utils.go index f2c236021..3d0db8b61 100644 --- a/agent/app/service/runtime_utils.go +++ b/agent/app/service/runtime_utils.go @@ -6,6 +6,8 @@ import ( "context" "encoding/json" "fmt" + "github.com/1Panel-dev/1Panel/agent/i18n" + "github.com/1Panel-dev/1Panel/agent/utils/common" "io" "os" "os/exec" @@ -319,7 +321,7 @@ func handleParams(create request.RuntimeCreate, projectDir string) (composeConte return } for k := range env { - if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") { + if strings.HasPrefix(k, "CONTAINER_PORT_") || strings.HasPrefix(k, "HOST_PORT_") || strings.HasPrefix(k, "HOST_IP_") || strings.Contains(k, "APP_PORT") { delete(env, k) } } @@ -431,18 +433,19 @@ func handleCompose(env gotenv.Env, composeContent []byte, create request.Runtime for name, service := range services { serviceName = name serviceValue = service.(map[string]interface{}) - _, ok := serviceValue["ports"].([]interface{}) - if ok { + delete(serviceValue, "ports") + if create.ExposedPorts != nil && len(create.ExposedPorts) > 0 { var ports []interface{} - ports = append(ports, "${HOST_IP}:${PANEL_APP_PORT_HTTP}:${APP_PORT}") for i, port := range create.ExposedPorts { containerPortStr := fmt.Sprintf("CONTAINER_PORT_%d", i) hostPortStr := fmt.Sprintf("HOST_PORT_%d", i) existMap[containerPortStr] = struct{}{} existMap[hostPortStr] = struct{}{} - ports = append(ports, fmt.Sprintf("${HOST_IP}:${%s}:${%s}", hostPortStr, containerPortStr)) + hostIPStr := fmt.Sprintf("HOST_IP_%d", i) + ports = append(ports, fmt.Sprintf("${%s}:${%s}:${%s}", hostIPStr, hostPortStr, containerPortStr)) create.Params[containerPortStr] = port.ContainerPort create.Params[hostPortStr] = port.HostPort + create.Params[hostIPStr] = port.HostIP } serviceValue["ports"] = ports } @@ -667,3 +670,34 @@ func getDockerComposeVolumes(yml []byte) ([]request.Volume, error) { } return res, nil } + +func checkRuntimePortExist(port int, scanPort bool, runtimeID uint) error { + errMap := make(map[string]interface{}) + errMap["port"] = port + appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithPort(port)) + if appInstall.ID > 0 { + errMap["type"] = i18n.GetMsgByKey("TYPE_APP") + errMap["name"] = appInstall.Name + return buserr.WithMap("ErrPortExist", errMap, nil) + } + opts := []repo.DBOption{runtimeRepo.WithPort(port)} + if runtimeID > 0 { + opts = append(opts, repo.WithByNOTID(runtimeID)) + } + runtime, _ := runtimeRepo.GetFirst(opts...) + if runtime != nil { + errMap["type"] = i18n.GetMsgByKey("TYPE_RUNTIME") + errMap["name"] = runtime.Name + return buserr.WithMap("ErrPortExist", errMap, nil) + } + domain, _ := websiteDomainRepo.GetFirst(websiteDomainRepo.WithPort(port)) + if domain.ID > 0 { + errMap["type"] = i18n.GetMsgByKey("TYPE_DOMAIN") + errMap["name"] = domain.Domain + return buserr.WithMap("ErrPortExist", errMap, nil) + } + if scanPort && common.ScanPort(port) { + return buserr.WithDetail("ErrPortInUsed", port, nil) + } + return nil +} diff --git a/agent/cmd/server/conf/app.yaml b/agent/cmd/server/conf/app.yaml index c49283ac0..415e74763 100644 --- a/agent/cmd/server/conf/app.yaml +++ b/agent/cmd/server/conf/app.yaml @@ -2,7 +2,7 @@ base: install_dir: /opt mode: dev -remote_rul: +remote_url: repo_url: https://resource.fit2cloud.com/1panel/package resource_url: https://resource.fit2cloud.com/1panel/resource app_repo: https://apps-assets.fit2cloud.com diff --git a/frontend/src/api/interface/runtime.ts b/frontend/src/api/interface/runtime.ts index 4ae8861b6..4eeb91ab1 100644 --- a/frontend/src/api/interface/runtime.ts +++ b/frontend/src/api/interface/runtime.ts @@ -65,6 +65,7 @@ export namespace Runtime { export interface ExposedPort { hostPort: number; containerPort: number; + hostIP: string; } export interface Environment { diff --git a/frontend/src/components/drawer-pro/index.vue b/frontend/src/components/drawer-pro/index.vue index d6bce07ce..7363c031c 100644 --- a/frontend/src/components/drawer-pro/index.vue +++ b/frontend/src/components/drawer-pro/index.vue @@ -1,5 +1,5 @@