mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-06 13:27:43 +08:00
fix: 解决应用安装升级状态错误的问题 (#5260)
This commit is contained in:
parent
e45f43da9a
commit
bdf8ba45ac
9 changed files with 192 additions and 129 deletions
|
@ -10,7 +10,7 @@ import (
|
|||
)
|
||||
|
||||
type AppRes struct {
|
||||
Items []*AppDTO `json:"items"`
|
||||
Items []*AppDto `json:"items"`
|
||||
Total int64 `json:"total"`
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,21 @@ type AppDTO struct {
|
|||
Tags []model.Tag `json:"tags"`
|
||||
}
|
||||
|
||||
type AppDto struct {
|
||||
Name string `json:"name"`
|
||||
Key string `json:"key"`
|
||||
ID uint `json:"ID"`
|
||||
ShortDescZh string `json:"shortDescZh"`
|
||||
ShortDescEn string `json:"shortDescEn"`
|
||||
Icon string `json:"icon"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Resource string `json:"resource"`
|
||||
Installed bool `json:"installed"`
|
||||
Versions []string `json:"versions"`
|
||||
Tags []model.Tag `json:"tags"`
|
||||
}
|
||||
|
||||
type TagDTO struct {
|
||||
model.Tag
|
||||
}
|
||||
|
@ -72,6 +87,27 @@ type AppInstalledDTO struct {
|
|||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
type AppInstallDTO struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
AppID uint `json:"appID"`
|
||||
AppDetailID uint `json:"appDetailID"`
|
||||
Version string `json:"version"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
HttpPort int `json:"httpPort"`
|
||||
HttpsPort int `json:"httpsPort"`
|
||||
Path string `json:"path"`
|
||||
CanUpdate bool `json:"canUpdate"`
|
||||
Icon string `json:"icon"`
|
||||
AppName string `json:"appName"`
|
||||
Ready int `json:"ready"`
|
||||
Total int `json:"total"`
|
||||
AppKey string `json:"appKey"`
|
||||
AppType string `json:"appType"`
|
||||
AppStatus string `json:"appStatus"`
|
||||
}
|
||||
|
||||
type DatabaseConn struct {
|
||||
Status string `json:"status"`
|
||||
Username string `json:"username"`
|
||||
|
|
|
@ -89,14 +89,21 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var appDTOs []*response.AppDTO
|
||||
var appDTOs []*response.AppDto
|
||||
for _, ap := range apps {
|
||||
ap.ReadMe = ""
|
||||
ap.Website = ""
|
||||
ap.Document = ""
|
||||
ap.Github = ""
|
||||
appDTO := &response.AppDTO{
|
||||
App: ap,
|
||||
appDTO := &response.AppDto{
|
||||
ID: ap.ID,
|
||||
Name: ap.Name,
|
||||
Key: ap.Key,
|
||||
Type: ap.Type,
|
||||
Icon: ap.Icon,
|
||||
ShortDescZh: ap.ShortDescZh,
|
||||
ShortDescEn: ap.ShortDescEn,
|
||||
Resource: ap.Resource,
|
||||
}
|
||||
appDTOs = append(appDTOs, appDTO)
|
||||
appTags, err := appTagRepo.GetByAppId(ap.ID)
|
||||
|
@ -436,6 +443,14 @@ func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (
|
|||
return
|
||||
}
|
||||
appInstall.Env = string(paramByte)
|
||||
|
||||
containerNames, err := getContainerNames(*appInstall)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if len(containerNames) > 0 {
|
||||
appInstall.ContainerName = strings.Join(containerNames, ",")
|
||||
}
|
||||
if err = appInstallRepo.Create(ctx, appInstall); err != nil {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -39,11 +39,11 @@ type AppInstallService struct {
|
|||
}
|
||||
|
||||
type IAppInstallService interface {
|
||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
|
||||
Page(req request.AppInstalledSearch) (int64, []response.AppInstallDTO, error)
|
||||
CheckExist(req request.AppInstalledInfo) (*response.AppInstalledCheck, error)
|
||||
LoadPort(req dto.OperationWithNameAndType) (int64, error)
|
||||
LoadConnInfo(req dto.OperationWithNameAndType) (response.DatabaseConn, error)
|
||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
|
||||
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstallDTO, error)
|
||||
Operate(req request.AppInstalledOperate) error
|
||||
Update(req request.AppInstalledUpdate) error
|
||||
IgnoreUpgrade(req request.AppInstalledIgnoreUpgrade) error
|
||||
|
@ -74,7 +74,7 @@ func (a *AppInstallService) GetInstallList() ([]dto.AppInstallInfo, error) {
|
|||
return datas, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
|
||||
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstallDTO, error) {
|
||||
var (
|
||||
opts []repo.DBOption
|
||||
total int64
|
||||
|
@ -191,7 +191,7 @@ func (a *AppInstallService) LoadConnInfo(req dto.OperationWithNameAndType) (resp
|
|||
return data, nil
|
||||
}
|
||||
|
||||
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
|
||||
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstallDTO, error) {
|
||||
var (
|
||||
installs []model.AppInstall
|
||||
err error
|
||||
|
@ -705,84 +705,27 @@ func syncAppInstallStatus(appInstall *model.AppInstall) error {
|
|||
if appInstall.Status == constant.Installing || appInstall.Status == constant.Rebuilding || appInstall.Status == constant.Upgrading {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
containerNames := []string{appInstall.ContainerName}
|
||||
if appInstall.ContainerName == "" {
|
||||
containerNames, err = getContainerNames(*appInstall)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cli, err := docker.NewClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cli.Close()
|
||||
|
||||
var containers []types.Container
|
||||
var (
|
||||
containers []types.Container
|
||||
containersMap map[string]types.Container
|
||||
containerNames = strings.Split(appInstall.ContainerName, ",")
|
||||
)
|
||||
containers, err = cli.ListContainersByName(containerNames)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var (
|
||||
runningCount int
|
||||
exitedCount int
|
||||
pausedCount int
|
||||
exitedContainerNames []string
|
||||
total = len(containerNames)
|
||||
count = len(containers)
|
||||
)
|
||||
|
||||
foundNames := make(map[string]bool)
|
||||
containersMap = make(map[string]types.Container)
|
||||
for _, con := range containers {
|
||||
foundNames[con.Names[0]] = true
|
||||
switch con.State {
|
||||
case "exited":
|
||||
exitedContainerNames = append(exitedContainerNames, strings.TrimPrefix(con.Names[0], "/"))
|
||||
exitedCount++
|
||||
case "running":
|
||||
runningCount++
|
||||
case "paused":
|
||||
pausedCount++
|
||||
}
|
||||
}
|
||||
|
||||
var notFoundNames []string
|
||||
for _, name := range containerNames {
|
||||
if !foundNames["/"+name] {
|
||||
notFoundNames = append(notFoundNames, name)
|
||||
}
|
||||
}
|
||||
|
||||
switch {
|
||||
case count == 0:
|
||||
if appInstall.Status != constant.Error {
|
||||
appInstall.Status = constant.SyncErr
|
||||
appInstall.Message = buserr.WithName("ErrContainerNotFound", strings.Join(containerNames, ",")).Error()
|
||||
}
|
||||
case exitedCount == total:
|
||||
appInstall.Status = constant.Stopped
|
||||
case runningCount == total:
|
||||
appInstall.Status = constant.Running
|
||||
case pausedCount == total:
|
||||
appInstall.Status = constant.Paused
|
||||
default:
|
||||
var msg string
|
||||
if exitedCount > 0 {
|
||||
msg = buserr.WithName("ErrContainerMsg", strings.Join(exitedContainerNames, ",")).Error()
|
||||
}
|
||||
if len(notFoundNames) > 0 {
|
||||
msg += buserr.WithName("ErrContainerNotFound", strings.Join(notFoundNames, ",")).Error()
|
||||
}
|
||||
if msg == "" {
|
||||
msg = buserr.New("ErrAppWarn").Error()
|
||||
}
|
||||
appInstall.Message = msg
|
||||
appInstall.Status = constant.UnHealthy
|
||||
containersMap[con.Names[0]] = con
|
||||
}
|
||||
synAppInstall(containersMap, appInstall)
|
||||
_ = appInstallRepo.Save(context.Background(), appInstall)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -937,6 +937,12 @@ func rebuildApp(appInstall model.AppInstall) error {
|
|||
_ = handleErr(appInstall, err, out)
|
||||
return
|
||||
}
|
||||
containerNames, err := getContainerNames(appInstall)
|
||||
if err != nil {
|
||||
_ = handleErr(appInstall, err, out)
|
||||
return
|
||||
}
|
||||
appInstall.ContainerName = strings.Join(containerNames, ",")
|
||||
|
||||
appInstall.Status = constant.Running
|
||||
_ = appInstallRepo.Save(context.Background(), &appInstall)
|
||||
|
@ -1119,10 +1125,65 @@ func handleErr(install model.AppInstall, err error, out string) error {
|
|||
return reErr
|
||||
}
|
||||
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) ([]response.AppInstalledDTO, error) {
|
||||
func doNotNeedSync(installed model.AppInstall) bool {
|
||||
return installed.Status == constant.Installing || installed.Status == constant.Rebuilding || installed.Status == constant.Upgrading || installed.Status == constant.Syncing
|
||||
}
|
||||
|
||||
func synAppInstall(containers map[string]types.Container, appInstall *model.AppInstall) {
|
||||
containerNames := strings.Split(appInstall.ContainerName, ",")
|
||||
if len(containers) == 0 {
|
||||
appInstall.Status = constant.Error
|
||||
appInstall.Message = buserr.WithName("ErrContainerNotFound", strings.Join(containerNames, ",")).Error()
|
||||
return
|
||||
}
|
||||
notFoundNames := make([]string, 0)
|
||||
exitNames := make([]string, 0)
|
||||
exitedCount := 0
|
||||
pausedCount := 0
|
||||
runningCount := 0
|
||||
total := len(containerNames)
|
||||
for _, name := range containerNames {
|
||||
if con, ok := containers["/"+name]; ok {
|
||||
switch con.State {
|
||||
case "exited":
|
||||
exitedCount++
|
||||
exitNames = append(exitNames, name)
|
||||
case "running":
|
||||
runningCount++
|
||||
case "paused":
|
||||
pausedCount++
|
||||
}
|
||||
} else {
|
||||
notFoundNames = append(notFoundNames, name)
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case exitedCount == total:
|
||||
appInstall.Status = constant.Stopped
|
||||
case runningCount == total:
|
||||
appInstall.Status = constant.Running
|
||||
case pausedCount == total:
|
||||
appInstall.Status = constant.Paused
|
||||
default:
|
||||
var msg string
|
||||
if exitedCount > 0 {
|
||||
msg = buserr.WithName("ErrContainerMsg", strings.Join(exitNames, ",")).Error()
|
||||
}
|
||||
if len(notFoundNames) > 0 {
|
||||
msg += buserr.WithName("ErrContainerNotFound", strings.Join(notFoundNames, ",")).Error()
|
||||
}
|
||||
if msg == "" {
|
||||
msg = buserr.New("ErrAppWarn").Error()
|
||||
}
|
||||
appInstall.Message = msg
|
||||
appInstall.Status = constant.UnHealthy
|
||||
}
|
||||
}
|
||||
|
||||
func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool) ([]response.AppInstallDTO, error) {
|
||||
var (
|
||||
res []response.AppInstalledDTO
|
||||
containers []types.Container
|
||||
res []response.AppInstallDTO
|
||||
containersMap map[string]types.Container
|
||||
)
|
||||
if sync {
|
||||
cli, err := docker.NewClient()
|
||||
|
@ -1130,41 +1191,38 @@ func handleInstalled(appInstallList []model.AppInstall, updated bool, sync bool)
|
|||
return nil, err
|
||||
}
|
||||
defer cli.Close()
|
||||
containers, err = cli.ListAllContainers()
|
||||
containers, err := cli.ListAllContainers()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
containersMap = make(map[string]types.Container, len(containers))
|
||||
for _, contain := range containers {
|
||||
containersMap[contain.Names[0]] = contain
|
||||
}
|
||||
}
|
||||
|
||||
for _, installed := range appInstallList {
|
||||
if updated && (installed.App.Type == "php" || installed.Status == constant.Installing || (installed.App.Key == constant.AppMysql && installed.Version == "5.6.51")) {
|
||||
continue
|
||||
}
|
||||
if sync {
|
||||
exist := false
|
||||
for _, contain := range containers {
|
||||
if contain.Names[0] == "/"+installed.ContainerName {
|
||||
exist = true
|
||||
switch contain.State {
|
||||
case "exited":
|
||||
installed.Status = constant.Stopped
|
||||
case "running":
|
||||
installed.Status = constant.Running
|
||||
case "paused":
|
||||
installed.Status = constant.Paused
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
installed.Status = constant.Error
|
||||
installed.Message = buserr.WithName("ErrContainerNotFound", installed.ContainerName).Error()
|
||||
}
|
||||
if sync && !doNotNeedSync(installed) {
|
||||
synAppInstall(containersMap, &installed)
|
||||
}
|
||||
|
||||
installDTO := response.AppInstalledDTO{
|
||||
AppInstall: installed,
|
||||
Path: installed.GetPath(),
|
||||
installDTO := response.AppInstallDTO{
|
||||
ID: installed.ID,
|
||||
Name: installed.Name,
|
||||
AppID: installed.AppId,
|
||||
AppDetailID: installed.AppDetailId,
|
||||
Version: installed.Version,
|
||||
Status: installed.Status,
|
||||
Message: installed.Message,
|
||||
HttpPort: installed.HttpPort,
|
||||
HttpsPort: installed.HttpsPort,
|
||||
Icon: installed.App.Icon,
|
||||
AppName: installed.App.Name,
|
||||
AppKey: installed.App.Key,
|
||||
AppType: installed.App.Type,
|
||||
}
|
||||
app, err := appRepo.GetFirst(commonRepo.WithByID(installed.AppId))
|
||||
if err != nil {
|
||||
|
|
|
@ -121,6 +121,27 @@ export namespace App {
|
|||
app: App;
|
||||
}
|
||||
|
||||
export interface AppInstallDto {
|
||||
id: number;
|
||||
name: string;
|
||||
appID: number;
|
||||
appDetailID: number;
|
||||
version: string;
|
||||
status: string;
|
||||
message: string;
|
||||
httpPort: number;
|
||||
httpsPort: number;
|
||||
path: string;
|
||||
canUpdate: boolean;
|
||||
icon: string;
|
||||
appName: string;
|
||||
ready: number;
|
||||
total: number;
|
||||
appKey: string;
|
||||
appType: string;
|
||||
appStatus: string;
|
||||
}
|
||||
|
||||
export interface AppInstalledInfo {
|
||||
id: number;
|
||||
key: string;
|
||||
|
|
|
@ -40,7 +40,7 @@ export const ChangePort = (params: App.ChangePort) => {
|
|||
};
|
||||
|
||||
export const SearchAppInstalled = (search: App.AppInstallSearch) => {
|
||||
return http.post<ResPage<App.AppInstalled>>('apps/installed/search', search);
|
||||
return http.post<ResPage<App.AppInstallDto>>('apps/installed/search', search);
|
||||
};
|
||||
|
||||
export const ListAppInstalled = () => {
|
||||
|
|
|
@ -73,7 +73,7 @@ const handleClose = () => {
|
|||
em('close', open);
|
||||
};
|
||||
|
||||
const acceptParams = async (app: App.AppInstalled) => {
|
||||
const acceptParams = async (app: App.AppInstallDto) => {
|
||||
deleteReq.value = {
|
||||
operate: 'delete',
|
||||
installId: 0,
|
||||
|
@ -83,7 +83,7 @@ const acceptParams = async (app: App.AppInstalled) => {
|
|||
};
|
||||
deleteInfo.value = '';
|
||||
deleteReq.value.installId = app.id;
|
||||
appType.value = app.app.type;
|
||||
appType.value = app.appType;
|
||||
deleteHelper.value = i18n.global.t('website.deleteConfirmHelper', [app.name]);
|
||||
appInstallName.value = app.name;
|
||||
open.value = true;
|
||||
|
|
|
@ -166,7 +166,6 @@ const acceptParams = async (props: ParamProps) => {
|
|||
submitModel.value.installId = props.id;
|
||||
params.value = [];
|
||||
paramData.value.id = props.id;
|
||||
paramData.value.app = props.app;
|
||||
paramModel.value.params = {};
|
||||
edit.value = false;
|
||||
await get();
|
||||
|
|
|
@ -100,11 +100,11 @@
|
|||
<el-card class="e-card">
|
||||
<el-row :gutter="20">
|
||||
<el-col :xs="3" :sm="3" :md="3" :lg="4" :xl="4">
|
||||
<div class="icon" @click.stop="openDetail(installed.app)">
|
||||
<div class="icon" @click.stop="openDetail(installed.appKey)">
|
||||
<el-avatar
|
||||
shape="square"
|
||||
:size="66"
|
||||
:src="'data:image/png;base64,' + installed.app.icon"
|
||||
:src="'data:image/png;base64,' + installed.icon"
|
||||
/>
|
||||
</div>
|
||||
</el-col>
|
||||
|
@ -168,7 +168,7 @@
|
|||
plain
|
||||
round
|
||||
size="small"
|
||||
@click="openUploads(installed.app.key, installed.name)"
|
||||
@click="openUploads(installed.appKey, installed.name)"
|
||||
v-if="mode === 'installed'"
|
||||
>
|
||||
{{ $t('database.loadBackup') }}
|
||||
|
@ -178,9 +178,7 @@
|
|||
plain
|
||||
round
|
||||
size="small"
|
||||
@click="
|
||||
openBackups(installed.app.key, installed.name, installed.status)
|
||||
"
|
||||
@click="openBackups(installed.appKey, installed.name, installed.status)"
|
||||
v-if="mode === 'installed'"
|
||||
>
|
||||
{{ $t('commons.button.backup') }}
|
||||
|
@ -203,7 +201,7 @@
|
|||
:disabled="
|
||||
(installed.status !== 'Running' &&
|
||||
installed.status !== 'UpgradeErr') ||
|
||||
installed.app.status === 'TakeDown'
|
||||
installed.appStatus === 'TakeDown'
|
||||
"
|
||||
@click="openOperate(installed, 'upgrade')"
|
||||
v-if="mode === 'upgrade'"
|
||||
|
@ -414,18 +412,12 @@ const getTagValue = (key: string) => {
|
|||
}
|
||||
};
|
||||
|
||||
const search = () => {
|
||||
loading.value = true;
|
||||
const search = async () => {
|
||||
searchReq.page = paginationConfig.currentPage;
|
||||
searchReq.pageSize = paginationConfig.pageSize;
|
||||
SearchAppInstalled(searchReq)
|
||||
.then((res) => {
|
||||
data.value = res.data.items;
|
||||
paginationConfig.total = res.data.total;
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
const res = await SearchAppInstalled(searchReq);
|
||||
data.value = res.data.items;
|
||||
paginationConfig.total = res.data.total;
|
||||
GetAppTags().then((res) => {
|
||||
tags.value = res.data;
|
||||
});
|
||||
|
@ -435,8 +427,8 @@ const goDashboard = async (port: any, protocol: string) => {
|
|||
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
||||
};
|
||||
|
||||
const openDetail = (app: App.App) => {
|
||||
appDetail.value.acceptParams(app.key, 'detail');
|
||||
const openDetail = (appKey: string) => {
|
||||
appDetail.value.acceptParams(appKey, 'detail');
|
||||
};
|
||||
|
||||
const openOperate = (row: any, op: string) => {
|
||||
|
@ -448,7 +440,7 @@ const openOperate = (row: any, op: string) => {
|
|||
AppInstalledDeleteCheck(row.id).then(async (res) => {
|
||||
const items = res.data;
|
||||
if (res.data && res.data.length > 0) {
|
||||
checkRef.value.acceptParams({ items: items, key: row.app.key, installID: row.id });
|
||||
checkRef.value.acceptParams({ items: items, key: row.appKey, installID: row.id });
|
||||
} else {
|
||||
deleteRef.value.acceptParams(row);
|
||||
}
|
||||
|
@ -475,10 +467,7 @@ const operate = async () => {
|
|||
}, 3000);
|
||||
setTimeout(() => {
|
||||
search();
|
||||
}, 5000);
|
||||
setTimeout(() => {
|
||||
search();
|
||||
}, 10000);
|
||||
}, 15000);
|
||||
})
|
||||
.catch(() => {
|
||||
search();
|
||||
|
@ -596,7 +585,7 @@ const openUploads = (key: string, name: string) => {
|
|||
};
|
||||
|
||||
const openParam = (row: any) => {
|
||||
appParamRef.value.acceptParams({ app: row.app, id: row.id });
|
||||
appParamRef.value.acceptParams({ id: row.id });
|
||||
};
|
||||
|
||||
const isAppErr = (row: any) => {
|
||||
|
@ -618,7 +607,9 @@ onMounted(() => {
|
|||
mode.value = 'upgrade';
|
||||
searchReq.update = true;
|
||||
}
|
||||
loading.value = true;
|
||||
search();
|
||||
loading.value = false;
|
||||
setTimeout(() => {
|
||||
searchReq.sync = true;
|
||||
search();
|
||||
|
|
Loading…
Add table
Reference in a new issue