1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-31 14:08:06 +08:00

feat: 优化应用升级逻辑 (#1075)

This commit is contained in:
zhengkunwang223 2023-05-18 16:48:19 +08:00 committed by GitHub
parent 72bc99bddc
commit d20d5946f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 370 additions and 201 deletions

View File

@ -59,14 +59,9 @@ type AppInstalledOperate struct {
}
type AppInstalledUpdate struct {
InstallId uint `json:"installId" validate:"required"`
Params map[string]interface{} `json:"params" validate:"required"`
Advanced bool `json:"advanced"`
CpuQuota float64 `json:"cpuQuota"`
MemoryLimit float64 `json:"memoryLimit"`
MemoryUnit string `json:"memoryUnit"`
ContainerName string `json:"containerName"`
AllowPort bool `json:"allowPort"`
InstallId uint `json:"installId" validate:"required"`
Params map[string]interface{} `json:"params" validate:"required"`
AppContainerConfig
}
type PortUpdate struct {

View File

@ -2,6 +2,7 @@ package response
import (
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"time"
"github.com/1Panel-dev/1Panel/backend/app/model"
@ -84,10 +85,6 @@ type AppParam struct {
}
type AppConfig struct {
Params []AppParam `json:"params"`
CpuQuota float64 `json:"cpuQuota"`
MemoryLimit float64 `json:"memoryLimit"`
MemoryUnit string `json:"memoryUnit"`
ContainerName string `json:"containerName"`
AllowPort bool `json:"allowPort"`
Params []AppParam `json:"params"`
request.AppContainerConfig
}

View File

@ -5,25 +5,23 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"io"
"net/http"
"os"
"path"
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/app/repo"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/common"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"gopkg.in/yaml.v3"
"io"
"net/http"
"os"
"path"
"strconv"
)
type AppService struct {
@ -301,50 +299,11 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
servicesMap[v] = servicesMap[k]
delete(servicesMap, k)
}
serviceValue := servicesMap[appInstall.ServiceName].(map[string]interface{})
if req.Advanced && (req.CpuQuota > 0 || req.MemoryLimit > 0) {
deploy := map[string]interface{}{
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
},
},
}
req.Params[constant.CPUS] = "0"
if req.CpuQuota > 0 {
req.Params[constant.CPUS] = req.CpuQuota
}
req.Params[constant.MemoryLimit] = "0"
if req.MemoryLimit > 0 {
req.Params[constant.MemoryLimit] = strconv.FormatFloat(req.MemoryLimit, 'f', -1, 32) + req.MemoryUnit
}
serviceValue["deploy"] = deploy
}
ports, ok := serviceValue["ports"].([]interface{})
if ok {
allowHost := "127.0.0.1"
if req.AllowPort {
allowHost = "0.0.0.0"
}
req.Params[constant.HostIP] = allowHost
for i, port := range ports {
portStr, portOK := port.(string)
if !portOK {
continue
}
portArray := strings.Split(portStr, ":")
if len(portArray) == 2 {
portArray = append([]string{"${HOST_IP}"}, portArray...)
}
ports[i] = strings.Join(portArray, ":")
}
serviceValue["ports"] = ports
if err = addDockerComposeCommonParam(composeMap, appInstall.ServiceName, req.AppContainerConfig, req.Params); err != nil {
return
}
servicesMap[appInstall.ServiceName] = serviceValue
var (
composeByte []byte
paramByte []byte
@ -379,14 +338,17 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
return
}
go func() {
if err = downloadApp(app, appDetail, appInstall, req); err != nil {
if err = copyData(app, appDetail, appInstall, req); err != nil {
if appInstall.Status == constant.Installing {
appInstall.Status = constant.Error
appInstall.Message = err.Error()
}
_ = appInstallRepo.Save(ctx, appInstall)
_ = appInstallRepo.Save(context.Background(), appInstall)
return
}
go func() {
_, _ = http.Get(appDetail.DownloadCallBackUrl)
}()
upApp(appInstall)
}()
go updateToolApp(appInstall)

View File

@ -5,11 +5,11 @@ import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/files"
"gopkg.in/yaml.v3"
"math"
"os"
"path"
"reflect"
"regexp"
"strconv"
"strings"
@ -262,23 +262,17 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
}
}
backupDockerCompose := installed.DockerCompose
if req.Advanced {
if req.ContainerName != "" {
req.Params[constant.ContainerName] = req.ContainerName
composeMap := make(map[string]interface{})
if err := addDockerComposeCommonParam(composeMap, installed.ServiceName, req.AppContainerConfig, req.Params); err != nil {
return err
}
req.Params[constant.CPUS] = "0"
if req.CpuQuota > 0 {
req.Params[constant.CPUS] = req.CpuQuota
composeByte, err := yaml.Marshal(composeMap)
if err != nil {
return err
}
req.Params[constant.MemoryLimit] = "0"
if req.MemoryLimit > 0 {
req.Params[constant.MemoryLimit] = strconv.FormatFloat(req.MemoryLimit, 'f', -1, 32) + req.MemoryUnit
}
allowHost := "127.0.0.1"
if req.AllowPort {
allowHost = "0.0.0.0"
}
req.Params[constant.HostIP] = allowHost
installed.DockerCompose = string(composeByte)
}
envPath := path.Join(installed.GetPath(), ".env")
@ -286,6 +280,7 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
if err != nil {
return err
}
backupEnvMaps := oldEnvMaps
handleMap(req.Params, oldEnvMaps)
paramByte, err := json.Marshal(oldEnvMaps)
if err != nil {
@ -295,36 +290,42 @@ func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
if err := env.Write(oldEnvMaps, envPath); err != nil {
return err
}
_ = appInstallRepo.Save(context.Background(), &installed)
fileOp := files.NewFileOp()
_ = fileOp.WriteFile(installed.GetComposePath(), strings.NewReader(installed.DockerCompose), 0755)
if err := rebuildApp(installed); err != nil {
_ = env.Write(backupEnvMaps, envPath)
_ = fileOp.WriteFile(installed.GetComposePath(), strings.NewReader(backupDockerCompose), 0755)
return err
}
installed.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &installed)
website, _ := websiteRepo.GetFirst(websiteRepo.WithAppInstallId(installed.ID))
if changePort && website.ID != 0 && website.Status == constant.Running {
nginxInstall, err := getNginxFull(&website)
if err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
config := nginxInstall.SiteConfig.Config
servers := config.FindServers()
if len(servers) == 0 {
return buserr.WithErr(constant.ErrUpdateBuWebsite, errors.New("nginx config is not valid"))
}
server := servers[0]
proxy := fmt.Sprintf("http://127.0.0.1:%d", installed.HttpPort)
server.UpdateRootProxy([]string{proxy})
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
if err := nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName); err != nil {
return buserr.WithErr(constant.ErrUpdateBuWebsite, err)
}
}
if changePort {
go func() {
_ = OperateFirewallPort(oldPorts, newPorts)
nginxInstall, err := getNginxFull(&website)
if err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error())
return
}
config := nginxInstall.SiteConfig.Config
servers := config.FindServers()
if len(servers) == 0 {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, errors.New("nginx config is not valid")).Error())
return
}
server := servers[0]
proxy := fmt.Sprintf("http://127.0.0.1:%d", installed.HttpPort)
server.UpdateRootProxy([]string{proxy})
if err := nginx.WriteConfig(config, nginx.IndentedStyle); err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error())
return
}
if err := nginxCheckAndReload(nginxInstall.SiteConfig.OldContent, config.FilePath, nginxInstall.Install.ContainerName); err != nil {
global.LOG.Errorf(buserr.WithErr(constant.ErrUpdateBuWebsite, err).Error())
return
}
}()
}
return nil
@ -543,31 +544,10 @@ func (a *AppInstallService) GetParams(id uint) (*response.AppConfig, error) {
params = append(params, appParam)
}
}
res.ContainerName = envs[constant.ContainerName].(string)
res.AllowPort = envs[constant.HostIP].(string) == "0.0.0.0"
numStr, ok := envs[constant.CPUS].(string)
if ok {
num, err := strconv.ParseFloat(numStr, 64)
if err == nil {
res.CpuQuota = num
}
}
num64, ok := envs[constant.CPUS].(float64)
if ok {
res.CpuQuota = num64
}
re := regexp.MustCompile(`(\d+(?:\.\d+)?)\s*([KMGT]?B)`)
matches := re.FindStringSubmatch(envs[constant.MemoryLimit].(string))
if len(matches) == 3 {
num, err := strconv.ParseFloat(matches[1], 64)
if err == nil {
unit := matches[2]
res.MemoryLimit = num
res.MemoryUnit = unit
}
}
config := getAppCommonConfig(envs)
res.Params = params
res.AppContainerConfig = config
return &res, nil
}

View File

@ -8,11 +8,14 @@ import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/compose-spec/compose-go/types"
"github.com/subosito/gotenv"
"gopkg.in/yaml.v3"
"math"
"net/http"
"os"
"os/exec"
"path"
"reflect"
"regexp"
"strconv"
"strings"
@ -226,40 +229,110 @@ func upgradeInstall(installId uint, detailId uint) error {
return err
}
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
if install.App.Resource == constant.AppResourceLocal {
detailDir = path.Join(constant.ResourceDir, "localApps", strings.TrimPrefix(install.App.Key, "local"), "versions", detail.Version)
}
install.Status = constant.Upgrading
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
stdout, err := cmd.CombinedOutput()
if err != nil {
if stdout != nil {
return errors.New(string(stdout))
}
return err
}
go func() {
var upErr error
defer func() {
if upErr != nil {
install.Status = constant.UpgradeErr
install.Message = err.Error()
_ = appInstallRepo.Save(context.Background(), &install)
}
}()
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
return errors.New(out)
if upErr = downloadApp(install.App, detail, &install); upErr != nil {
return
}
return err
}
install.DockerCompose = detail.DockerCompose
install.Version = detail.Version
install.AppDetailId = detailId
fileOp := files.NewFileOp()
if err := fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); err != nil {
return err
}
if out, err := compose.Up(install.GetComposePath()); err != nil {
if out != "" {
return errors.New(out)
detailDir := path.Join(constant.ResourceDir, "apps", install.App.Resource, install.App.Key, detail.Version)
if install.App.Resource == constant.AppResourceLocal {
detailDir = path.Join(constant.ResourceDir, "apps", "local", strings.TrimPrefix(install.App.Key, "local"), detail.Version)
}
return err
}
cmd := exec.Command("/bin/bash", "-c", fmt.Sprintf("cp -rf %s/* %s", detailDir, install.GetPath()))
stdout, err := cmd.CombinedOutput()
if err != nil {
if stdout != nil {
upErr = errors.New(string(stdout))
return
}
upErr = err
return
}
composeMap := make(map[string]interface{})
if upErr = yaml.Unmarshal([]byte(detail.DockerCompose), &composeMap); upErr != nil {
return
}
value, ok := composeMap["services"]
if !ok {
upErr = buserr.New(constant.ErrFileParse)
return
}
servicesMap := value.(map[string]interface{})
index := 0
oldServiceName := ""
for k := range servicesMap {
oldServiceName = k
index++
if index > 0 {
break
}
}
servicesMap[install.ServiceName] = servicesMap[oldServiceName]
delete(servicesMap, oldServiceName)
envs := make(map[string]interface{})
if upErr = json.Unmarshal([]byte(install.Env), &envs); upErr != nil {
return
}
config := getAppCommonConfig(envs)
config.Advanced = true
if upErr = addDockerComposeCommonParam(composeMap, install.ServiceName, config, envs); upErr != nil {
return
}
paramByte, upErr := json.Marshal(envs)
if upErr != nil {
return
}
install.Env = string(paramByte)
composeByte, upErr := yaml.Marshal(composeMap)
if upErr != nil {
return
}
install.DockerCompose = string(composeByte)
install.Version = detail.Version
install.AppDetailId = detailId
go func() {
_, _ = http.Get(detail.DownloadCallBackUrl)
}()
if out, err := compose.Down(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
return
}
fileOp := files.NewFileOp()
if upErr = fileOp.WriteFile(install.GetComposePath(), strings.NewReader(install.DockerCompose), 0775); upErr != nil {
return
}
if out, err := compose.Up(install.GetComposePath()); err != nil {
if out != "" {
upErr = errors.New(out)
return
}
upErr = err
return
}
install.Status = constant.Running
_ = appInstallRepo.Save(context.Background(), &install)
}()
return appInstallRepo.Save(context.Background(), &install)
}
@ -332,32 +405,51 @@ func handleMap(params map[string]interface{}, envParams map[string]string) {
}
}
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall, req request.AppInstallCreate) (err error) {
func downloadApp(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall) (err error) {
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
if !appDetail.Update {
return
}
fileOp := files.NewFileOp()
appDownloadDir := path.Join(appResourceDir, app.Key)
if !fileOp.Stat(appDownloadDir) {
_ = fileOp.CreateDir(appDownloadDir, 0755)
}
appVersionDir := path.Join(appDownloadDir, appDetail.Version)
if !fileOp.Stat(appVersionDir) {
_ = fileOp.CreateDir(appVersionDir, 0755)
}
global.LOG.Infof("download app[%s] from %s", app.Name, appDetail.DownloadUrl)
filePath := path.Join(appVersionDir, appDetail.Version+".tar.gz")
defer func() {
if err != nil {
appInstall.Status = constant.DownloadErr
appInstall.Message = err.Error()
}
}()
if err = fileOp.DownloadFile(appDetail.DownloadUrl, filePath); err != nil {
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
return
}
if err = fileOp.Decompress(filePath, appVersionDir, files.TarGz); err != nil {
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
return
}
_ = fileOp.DeleteFile(filePath)
return
}
func copyData(app model.App, appDetail model.AppDetail, appInstall *model.AppInstall, req request.AppInstallCreate) (err error) {
fileOp := files.NewFileOp()
appResourceDir := path.Join(constant.AppResourceDir, app.Resource)
if app.Resource == constant.AppResourceRemote && appDetail.Update {
appDownloadDir := path.Join(appResourceDir, app.Key)
if !fileOp.Stat(appDownloadDir) {
_ = fileOp.CreateDir(appDownloadDir, 0755)
}
appVersionDir := path.Join(appDownloadDir, appDetail.Version)
if !fileOp.Stat(appVersionDir) {
_ = fileOp.CreateDir(appVersionDir, 0755)
}
global.LOG.Infof("download app[%s] from %s", app.Name, appDetail.DownloadUrl)
filePath := path.Join(appVersionDir, appDetail.Version+".tar.gz")
if err = fileOp.DownloadFile(appDetail.DownloadUrl, filePath); err != nil {
appInstall.Status = constant.DownloadErr
global.LOG.Errorf("download app[%s] error %v", app.Name, err)
if app.Resource == constant.AppResourceRemote {
err = downloadApp(app, appDetail, appInstall)
if err != nil {
return
}
if err = fileOp.Decompress(filePath, appVersionDir, files.TarGz); err != nil {
global.LOG.Errorf("decompress app[%s] error %v", app.Name, err)
appInstall.Status = constant.DownloadErr
return
}
_ = fileOp.DeleteFile(filePath)
}
appKey := app.Key
installAppDir := path.Join(constant.AppInstallDir, app.Key)
@ -639,3 +731,108 @@ func updateToolApp(installed *model.AppInstall) {
return
}
}
func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName string, req request.AppContainerConfig, params map[string]interface{}) error {
services, serviceValid := composeMap["services"].(map[string]interface{})
if !serviceValid {
return buserr.New(constant.ErrFileParse)
}
service, serviceExist := services[serviceName]
if !serviceExist {
return buserr.New(constant.ErrFileParse)
}
serviceValue := service.(map[string]interface{})
deploy := map[string]interface{}{
"resources": map[string]interface{}{
"limits": map[string]interface{}{
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
},
},
}
serviceValue["deploy"] = deploy
ports, ok := serviceValue["ports"].([]interface{})
if ok {
for i, port := range ports {
portStr, portOK := port.(string)
if !portOK {
continue
}
portArray := strings.Split(portStr, ":")
if len(portArray) == 2 {
portArray = append([]string{"${HOST_IP}"}, portArray...)
}
ports[i] = strings.Join(portArray, ":")
}
serviceValue["ports"] = ports
}
params[constant.CPUS] = "0"
params[constant.MemoryLimit] = "0"
if req.Advanced {
if req.CpuQuota > 0 {
params[constant.CPUS] = req.CpuQuota
}
if req.MemoryLimit > 0 {
params[constant.MemoryLimit] = strconv.FormatFloat(req.MemoryLimit, 'f', -1, 32) + req.MemoryUnit
}
}
_, portExist := serviceValue["ports"].([]interface{})
if portExist {
allowHost := "127.0.0.1"
if req.Advanced && req.AllowPort {
allowHost = "0.0.0.0"
}
params[constant.HostIP] = allowHost
}
services[serviceName] = serviceValue
return nil
}
func getAppCommonConfig(envs map[string]interface{}) request.AppContainerConfig {
config := request.AppContainerConfig{}
if hostIp, ok := envs[constant.HostIP]; ok {
config.AllowPort = hostIp.(string) == "0.0.0.0"
} else {
config.AllowPort = true
}
if cpuCore, ok := envs[constant.CPUS]; ok {
numStr, ok := cpuCore.(string)
if ok {
num, err := strconv.ParseFloat(numStr, 64)
if err == nil {
config.CpuQuota = num
}
} else {
num64, flOk := cpuCore.(float64)
if flOk {
config.CpuQuota = num64
}
}
} else {
config.CpuQuota = 0
}
if memLimit, ok := envs[constant.MemoryLimit]; ok {
re := regexp.MustCompile(`(\d+(?:\.\d+)?)\s*([KMGT]?B)`)
matches := re.FindStringSubmatch(memLimit.(string))
if len(matches) == 3 {
num, err := strconv.ParseFloat(matches[1], 64)
if err == nil {
unit := matches[2]
config.MemoryLimit = num
config.MemoryUnit = unit
}
}
} else {
config.MemoryLimit = 0
config.MemoryUnit = "M"
}
if containerName, ok := envs[constant.ContainerName]; ok {
config.ContainerName = containerName.(string)
}
return config
}

View File

@ -9,6 +9,8 @@ const (
Syncing = "Syncing"
DownloadErr = "DownloadErr"
DirNotFound = "DirNotFound"
Upgrading = "Upgrading"
UpgradeErr = "UpgradeErr"
ContainerPrefix = "1Panel-"

View File

@ -5,31 +5,31 @@ import (
)
func Up(filePath string) (string, error) {
stdout, err := cmd.Execf("docker-compose -f %s up -d", filePath)
stdout, err := cmd.Execf("docker compose -f %s up -d", filePath)
return stdout, err
}
func Down(filePath string) (string, error) {
stdout, err := cmd.Execf("docker-compose -f %s down --remove-orphans", filePath)
stdout, err := cmd.Execf("docker compose -f %s down --remove-orphans", filePath)
return stdout, err
}
func Start(filePath string) (string, error) {
stdout, err := cmd.Execf("docker-compose -f %s start", filePath)
stdout, err := cmd.Execf("docker compose -f %s start", filePath)
return stdout, err
}
func Stop(filePath string) (string, error) {
stdout, err := cmd.Execf("docker-compose -f %s stop", filePath)
stdout, err := cmd.Execf("docker compose -f %s stop", filePath)
return stdout, err
}
func Restart(filePath string) (string, error) {
stdout, err := cmd.Execf("docker-compose -f %s restart", filePath)
stdout, err := cmd.Execf("docker compose -f %s restart", filePath)
return stdout, err
}
func Operate(filePath, operation string) (string, error) {
stdout, err := cmd.Execf("docker-compose -f %s %s", filePath, operation)
stdout, err := cmd.Execf("docker compose -f %s %s", filePath, operation)
return stdout, err
}

View File

@ -477,12 +477,16 @@ func (f FileOp) Compress(srcRiles []string, dst string, name string, cType Compr
return nil
}
func isIgnoreFile(name string) bool {
return strings.HasPrefix(name, "__MACOSX") || strings.HasSuffix(name, ".DS_Store") || strings.HasPrefix(name, "._")
}
func (f FileOp) Decompress(srcFile string, dst string, cType CompressType) error {
format := getFormat(cType)
handler := func(ctx context.Context, archFile archiver.File) error {
info := archFile.FileInfo
if strings.HasPrefix(archFile.NameInArchive, "__MACOSX") {
if isIgnoreFile(archFile.Name()) {
return nil
}
filePath := filepath.Join(dst, archFile.NameInArchive)

View File

@ -19,11 +19,12 @@ const props = defineProps({
let status = ref('running');
const getType = (status: string) => {
if (status.includes('error') || status.includes('err')) {
return 'danger';
}
switch (status) {
case 'running':
return 'success';
case 'error':
return 'danger';
case 'stopped':
return 'danger';
default:
@ -31,7 +32,7 @@ const getType = (status: string) => {
}
};
const loadingStatus = ['installing', 'building', 'restarting'];
const loadingStatus = ['installing', 'building', 'restarting', 'upgrading'];
const loadingIcon = (status: string): boolean => {
return loadingStatus.indexOf(status) > -1;

View File

@ -196,6 +196,8 @@ const message = {
disabled: 'Disabled',
normal: 'Normal',
building: 'Building',
downloaderr: 'Download Error',
upgrading: 'Upgrading',
},
},
menu: {
@ -1091,6 +1093,7 @@ const message = {
'Allowing external port access will release the firewall port, please do not release the php operating environment',
appInstallWarn:
'The application does not release the external access port by default, you can choose to release it in the advanced settings',
upgradeStart: 'Start upgrading! Please refresh the page later',
},
website: {
website: 'Website',

View File

@ -201,6 +201,8 @@ const message = {
disabled: '已停止',
normal: '正常',
building: '制作镜像中',
downloaderr: '下载失败',
upgrading: '升级中',
},
units: {
second: '秒',
@ -1089,6 +1091,7 @@ const message = {
allowPort: '端口外部访问',
allowPortHelper: '允许外部端口访问会放开防火墙端口php运行环境请勿放开',
appInstallWarn: '应用默认不放开外部访问端口可以在高级设置中选择放开',
upgradeStart: '开始升级请稍后刷新页面',
},
website: {
website: '网站',

View File

@ -24,6 +24,9 @@
float: right;
margin-right: 10px;
}
.msg {
margin-left: 10px;
}
}
.d-description {

View File

@ -179,7 +179,7 @@ const get = async () => {
}
paramModel.value.memoryLimit = res.data.memoryLimit;
paramModel.value.cpuQuota = res.data.cpuQuota;
paramModel.value.memoryUnit = res.data.memoryUnit;
paramModel.value.memoryUnit = res.data.memoryUnit !== '' ? res.data.memoryUnit : 'MB';
paramModel.value.allowPort = res.data.allowPort;
paramModel.value.containerName = res.data.containerName;
paramModel.value.advanced = false;

View File

@ -81,25 +81,25 @@
<el-col :xs="21" :sm="21" :md="21" :lg="20" :xl="20">
<div class="a-detail">
<div class="d-name">
<span class="name">{{ installed.name }}</span>
<el-button link type="info">
<span class="name">{{ installed.name }}</span>
</el-button>
<span class="status">
<Status :key="installed.status" :status="installed.status"></Status>
</span>
<span class="msg">
<el-popover
v-if="installed.status === 'Error'"
v-if="isAppErr(installed)"
placement="bottom"
:width="400"
trigger="hover"
:content="installed.message"
>
<template #reference>
<Status
:key="installed.status"
:status="installed.status"
></Status>
<el-button link type="primary">详情</el-button>
</template>
</el-popover>
<span v-else>
<Status :key="installed.status" :status="installed.status"></Status>
</span>
</span>
<el-button
@ -132,6 +132,7 @@
plain
round
size="small"
:disabled="installed.status === 'Upgrading'"
@click="openOperate(installed, 'upgrade')"
v-if="mode === 'upgrade'"
>
@ -337,18 +338,27 @@ const buttons = [
click: (row: any) => {
openOperate(row, 'sync');
},
disabled: (row: any) => {
return row.status === 'DownloadErr' || row.status === 'Upgrading';
},
},
{
label: i18n.global.t('app.rebuild'),
click: (row: any) => {
openOperate(row, 'rebuild');
},
disabled: (row: any) => {
return row.status === 'DownloadErr' || row.status === 'Upgrading';
},
},
{
label: i18n.global.t('app.restart'),
click: (row: any) => {
openOperate(row, 'restart');
},
disabled: (row: any) => {
return row.status === 'DownloadErr' || row.status === 'Upgrading';
},
},
{
label: i18n.global.t('app.start'),
@ -356,7 +366,12 @@ const buttons = [
openOperate(row, 'start');
},
disabled: (row: any) => {
return row.status === 'Running' || row.status === 'Error';
return (
row.status === 'Running' ||
row.status === 'Error' ||
row.status === 'DownloadErr' ||
row.status === 'Upgrading'
);
},
},
{
@ -365,7 +380,7 @@ const buttons = [
openOperate(row, 'stop');
},
disabled: (row: any) => {
return row.status !== 'Running';
return row.status !== 'Running' || row.status === 'DownloadErr' || row.status === 'Upgrading';
},
},
{
@ -379,6 +394,9 @@ const buttons = [
click: (row: any) => {
openParam(row.id);
},
disabled: (row: any) => {
return row.status === 'DownloadErr' || row.status === 'Upgrading';
},
},
];
@ -404,6 +422,10 @@ const openParam = (installId: number) => {
appParamRef.value.acceptParams({ id: installId });
};
const isAppErr = (row: any) => {
return row.status.includes('Err') || row.status.includes('Error');
};
onMounted(() => {
const path = router.currentRoute.value.path;
if (path == '/apps/upgrade') {

View File

@ -83,7 +83,7 @@ const operate = async () => {
loading.value = true;
await InstalledOp(operateReq)
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
MsgSuccess(i18n.global.t('app.upgradeStart'));
bus.emit('upgrade', true);
handleClose();
})