Skip to content

Commit 4087a7a

Browse files
feat: Added progress display for image pulling (#7955)
1 parent b80c55c commit 4087a7a

File tree

9 files changed

+99
-29
lines changed

9 files changed

+99
-29
lines changed

agent/app/service/app_utils.go

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -612,17 +612,15 @@ func upgradeInstall(req request.AppInstallUpgrade) error {
612612
if err != nil {
613613
return err
614614
}
615+
dockerCLi, err := docker.NewClient()
615616
if req.PullImage {
616617
images, err := composeV2.GetDockerComposeImagesV2(content, []byte(detail.DockerCompose))
617618
if err != nil {
618619
return err
619620
}
620621
for _, image := range images {
621622
t.Log(i18n.GetWithName("PullImageStart", image))
622-
if out, err := cmd.ExecWithTimeOut("docker pull "+image, 20*time.Minute); err != nil {
623-
if out != "" {
624-
err = errors.New(out)
625-
}
623+
if err = dockerCLi.PullImageWithProcess(t, image); err != nil {
626624
err = buserr.WithNameAndErr("ErrDockerPullImage", "", err)
627625
return err
628626
}
@@ -1046,6 +1044,10 @@ func upApp(task *task.Task, appInstall *model.AppInstall, pullImages bool) error
10461044
return err
10471045
}
10481046
imagePrefix := xpack.GetImagePrefix()
1047+
dockerCLi, err := docker.NewClient()
1048+
if err != nil {
1049+
return err
1050+
}
10491051
for _, image := range images {
10501052
if imagePrefix != "" {
10511053
lastSlashIndex := strings.LastIndex(image, "/")
@@ -1054,17 +1056,19 @@ func upApp(task *task.Task, appInstall *model.AppInstall, pullImages bool) error
10541056
}
10551057
image = imagePrefix + "/" + image
10561058
}
1059+
10571060
task.Log(i18n.GetWithName("PullImageStart", image))
1058-
if out, err = cmd.ExecWithTimeOut("docker pull "+image, 20*time.Minute); err != nil {
1059-
if out != "" {
1060-
if strings.Contains(out, "no such host") {
1061+
if err = dockerCLi.PullImageWithProcess(task, image); err != nil {
1062+
errOur := err.Error()
1063+
if errOur != "" {
1064+
if strings.Contains(errOur, "no such host") {
10611065
errMsg = i18n.GetMsgByKey("ErrNoSuchHost") + ":"
10621066
}
1063-
if strings.Contains(out, "timeout") {
1067+
if strings.Contains(errOur, "timeout") {
10641068
errMsg = i18n.GetMsgByKey("ErrImagePullTimeOut") + ":"
10651069
}
10661070
}
1067-
appInstall.Message = errMsg + out
1071+
appInstall.Message = errMsg + errOur
10681072
installErr := errors.New(appInstall.Message)
10691073
task.LogFailedWithErr(i18n.GetMsgByKey("PullImage"), installErr)
10701074
return installErr

agent/app/service/website.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1375,7 +1375,7 @@ func (w WebsiteService) ChangePHPVersion(req request.WebsitePHPVersionReq) error
13751375
return buserr.New("ErrPHPResource")
13761376
}
13771377
website.RuntimeID = req.RuntimeID
1378-
phpProxy := fmt.Sprintf("127.0.0.1:%d", runtime.Port)
1378+
phpProxy := fmt.Sprintf("127.0.0.1:%s", runtime.Port)
13791379
website.Proxy = phpProxy
13801380
server.UpdatePHPProxy([]string{website.Proxy}, "")
13811381
website.Type = constant.Runtime

agent/app/service/website_utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ func opWebsite(website *model.Website, operate string) error {
849849
}
850850
server.UpdatePHPProxy([]string{website.Proxy}, localPath)
851851
} else {
852-
proxy := fmt.Sprintf("http://127.0.0.1:%d", runtime.Port)
852+
proxy := fmt.Sprintf("http://127.0.0.1:%s", runtime.Port)
853853
server.UpdateRootProxy([]string{proxy})
854854
}
855855
}

agent/app/task/task.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package task
22

33
import (
4+
"bufio"
45
"context"
56
"fmt"
67
"log"
@@ -26,6 +27,7 @@ type Task struct {
2627
Name string
2728
TaskID string
2829
Logger *log.Logger
30+
Writer *bufio.Writer
2931
SubTasks []*SubTask
3032
Rollbacks []RollbackFunc
3133
logFile *os.File
@@ -111,6 +113,7 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
111113
if err != nil {
112114
return nil, fmt.Errorf("failed to open log file: %w", err)
113115
}
116+
writer := bufio.NewWriter(file)
114117
logger := log.New(file, "", log.LstdFlags)
115118
taskModel := &model.Task{
116119
ID: taskID,
@@ -122,7 +125,7 @@ func NewTask(name, operate, taskScope, taskID string, resourceID uint) (*Task, e
122125
Operate: operate,
123126
}
124127
taskRepo := repo.NewITaskRepo()
125-
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel}
128+
task := &Task{Name: name, logFile: file, Logger: logger, taskRepo: taskRepo, Task: taskModel, Writer: writer}
126129
return task, nil
127130
}
128131

agent/utils/docker/docker.go

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,21 @@ package docker
22

33
import (
44
"context"
5-
"github.com/docker/docker/api/types/network"
6-
7-
"github.com/docker/docker/api/types/container"
8-
"github.com/docker/docker/api/types/image"
9-
5+
"encoding/json"
6+
"fmt"
107
"github.com/1Panel-dev/1Panel/agent/app/model"
8+
"github.com/1Panel-dev/1Panel/agent/app/task"
119
"github.com/1Panel-dev/1Panel/agent/global"
12-
1310
"github.com/docker/docker/api/types"
11+
"github.com/docker/docker/api/types/container"
1412
"github.com/docker/docker/api/types/filters"
13+
"github.com/docker/docker/api/types/image"
14+
"github.com/docker/docker/api/types/network"
1515
"github.com/docker/docker/client"
16+
"io"
17+
"os"
18+
"strings"
19+
"time"
1620
)
1721

1822
func NewDockerClient() (*client.Client, error) {
@@ -28,10 +32,6 @@ func NewDockerClient() (*client.Client, error) {
2832
return cli, nil
2933
}
3034

31-
type Client struct {
32-
cli *client.Client
33-
}
34-
3535
func NewClient() (Client, error) {
3636
var settingItem model.Setting
3737
_ = global.DB.Where("key = ?", "DockerSockPath").First(&settingItem).Error
@@ -48,10 +48,8 @@ func NewClient() (Client, error) {
4848
}, nil
4949
}
5050

51-
func NewClientWithCli(cli *client.Client) (Client, error) {
52-
return Client{
53-
cli: cli,
54-
}, nil
51+
type Client struct {
52+
cli *client.Client
5553
}
5654

5755
func (c Client) Close() {
@@ -142,6 +140,7 @@ func CreateDefaultDockerNetwork() error {
142140
global.LOG.Errorf("init docker client error %s", err.Error())
143141
return err
144142
}
143+
145144
defer cli.Close()
146145
if !cli.NetworkExist("1panel-network") {
147146
if err := cli.CreateNetwork("1panel-network"); err != nil {
@@ -151,3 +150,66 @@ func CreateDefaultDockerNetwork() error {
151150
}
152151
return nil
153152
}
153+
154+
func setLog(id, newLastLine string, task *task.Task) error {
155+
data, err := os.ReadFile(task.Task.LogFile)
156+
if err != nil {
157+
return fmt.Errorf("failed to read file: %v", err)
158+
}
159+
lines := strings.Split(string(data), "\n")
160+
exist := false
161+
for index, line := range lines {
162+
if strings.Contains(line, id) {
163+
lines[index] = newLastLine
164+
exist = true
165+
break
166+
}
167+
}
168+
if !exist {
169+
task.Log(newLastLine)
170+
return nil
171+
}
172+
output := strings.Join(lines, "\n")
173+
_ = os.WriteFile(task.Task.LogFile, []byte(output), os.ModePerm)
174+
return nil
175+
}
176+
177+
func (c Client) PullImageWithProcess(task *task.Task, imageName string) error {
178+
out, err := c.cli.ImagePull(context.Background(), imageName, image.PullOptions{})
179+
if err != nil {
180+
return err
181+
}
182+
defer out.Close()
183+
decoder := json.NewDecoder(out)
184+
for {
185+
var progress map[string]interface{}
186+
if err = decoder.Decode(&progress); err != nil {
187+
if err == io.EOF {
188+
break
189+
}
190+
return err
191+
}
192+
timeStr := time.Now().Format("2006/01/02 15:04:05")
193+
status, _ := progress["status"].(string)
194+
if status == "Downloading" || status == "Extracting" {
195+
id, _ := progress["id"].(string)
196+
progressDetail, _ := progress["progressDetail"].(map[string]interface{})
197+
current, _ := progressDetail["current"].(float64)
198+
progressStr := ""
199+
total, ok := progressDetail["total"].(float64)
200+
if ok {
201+
progressStr = fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, (current/total)*100)
202+
} else {
203+
progressStr = fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, current)
204+
}
205+
206+
_ = setLog(id, progressStr, task)
207+
}
208+
if status == "Pull complete" || status == "Download complete" {
209+
id, _ := progress["id"].(string)
210+
progressStr := fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, 100.0)
211+
_ = setLog(id, progressStr, task)
212+
}
213+
}
214+
return nil
215+
}

core/constant/common.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ var WebUrlMap = map[string]struct{}{
126126
"/xpack/waf/websites": {},
127127
"/xpack/waf/log": {},
128128
"/xpack/waf/block": {},
129+
"/xpack/waf/blackwhite": {},
129130
"/xpack/monitor/dashboard": {},
130131
"/xpack/monitor/setting": {},
131132
"/xpack/monitor/rank": {},

frontend/src/views/log/task/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ const search = async () => {
8585
};
8686
8787
const openTaskLog = (row: Log.Task) => {
88-
taskLogRef.value.openWithTaskID(row.id, !(row.status == 'Executing'));
88+
taskLogRef.value.openWithTaskID(row.id, row.status == 'Executing');
8989
};
9090
9191
onMounted(() => {

frontend/src/views/login/components/login-form.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<template>
2-
<div class="w-full h-full flex items-center justify-center px-8 py-6">
2+
<div class="w-full h-full flex items-center justify-center px-8">
33
<div v-loading="loading" class="w-full flex-grow flex flex-col">
44
<div v-if="mfaShow">
55
<el-form @submit.prevent>

frontend/src/views/login/index.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
class="bg-white shadow-lg relative z-10 border border-gray-200 flex overflow-hidden"
1010
>
1111
<div class="grid grid-cols-1 md:grid-cols-2 items-stretch w-full h-full">
12-
<div v-if="showLogo" class="flex flex-col justify-center items-center w-full">
12+
<div v-if="showLogo">
1313
<img :src="logoImage" class="max-w-full max-h-full object-contain" />
1414
</div>
1515
<div :class="loginFormClass">

0 commit comments

Comments
 (0)