diff --git a/agent/app/service/image.go b/agent/app/service/image.go index adfff0779..4ada15fdb 100644 --- a/agent/app/service/image.go +++ b/agent/app/service/image.go @@ -203,17 +203,10 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) error { go func() { defer tar.Close() taskItem.AddSubTask(i18n.GetMsgByKey("ImageBuild"), func(t *task.Task) error { - res, err := client.ImageBuild(context.Background(), tar, opts) - if err != nil { + dockerCli := docker.NewClientWithExist(client) + if err := dockerCli.BuildImageWithProcessAndOptions(taskItem, tar, opts); err != nil { return err } - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - if strings.Contains(string(body), "errorDetail") || strings.Contains(string(body), "error:") { - taskItem.LogWithStatus(i18n.GetMsgByKey("ImageBuildStdoutCheck"), fmt.Errorf("build image %s failed", req.Name)) - return err - } - taskItem.LogSuccess(i18n.GetWithName("ImaegBuildRes", "\n"+string(body))) return nil }, nil) @@ -381,13 +374,10 @@ func (u *ImageService) ImagePush(req dto.ImagePush) error { return nil }, nil) taskItem.AddSubTask(i18n.GetMsgByKey("TaskPush"), func(t *task.Task) error { - out, err := client.ImagePush(context.TODO(), newName, options) - if err != nil { + dockerCli := docker.NewClientWithExist(client) + if err := dockerCli.PushImageWithProcessAndOptions(taskItem, newName, options); err != nil { return err } - defer out.Close() - body, _ := io.ReadAll(out) - taskItem.Log(i18n.GetWithName("ImaegPushRes", "\n"+string(body))) return nil }, nil) _ = taskItem.Execute() diff --git a/agent/utils/docker/docker.go b/agent/utils/docker/docker.go index 852f4a21c..d30504e5c 100644 --- a/agent/utils/docker/docker.go +++ b/agent/utils/docker/docker.go @@ -4,6 +4,11 @@ import ( "context" "encoding/json" "fmt" + "io" + "os" + "strings" + "time" + "github.com/1Panel-dev/1Panel/agent/app/model" "github.com/1Panel-dev/1Panel/agent/app/task" "github.com/1Panel-dev/1Panel/agent/global" @@ -13,10 +18,6 @@ import ( "github.com/docker/docker/api/types/image" "github.com/docker/docker/api/types/network" "github.com/docker/docker/client" - "io" - "os" - "strings" - "time" ) func NewDockerClient() (*client.Client, error) { @@ -220,6 +221,111 @@ func (c Client) PullImageWithProcessAndOptions(task *task.Task, imageName string return nil } +func (c Client) PushImageWithProcessAndOptions(task *task.Task, imageName string, options image.PushOptions) error { + out, err := c.cli.ImagePush(context.Background(), imageName, options) + if err != nil { + return err + } + defer out.Close() + decoder := json.NewDecoder(out) + for { + var progress map[string]interface{} + if err = decoder.Decode(&progress); err != nil { + if err == io.EOF { + break + } + return err + } + if msg, ok := progress["errorDetail"]; ok { + return fmt.Errorf("image push failed, err: %v", msg) + } + if msg, ok := progress["error"]; ok { + return fmt.Errorf("image push failed, err: %v", msg) + } + timeStr := time.Now().Format("2006/01/02 15:04:05") + status, _ := progress["status"].(string) + switch status { + case "Pushing": + id, _ := progress["id"].(string) + progressDetail, _ := progress["progressDetail"].(map[string]interface{}) + current, _ := progressDetail["current"].(float64) + progressStr := "" + total, ok := progressDetail["total"].(float64) + if ok { + progressStr = fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, (current/total)*100) + } else { + progressStr = fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, current) + } + + _ = setLog(id, progressStr, task) + case "Pushed": + id, _ := progress["id"].(string) + progressStr := fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, 100.0) + _ = setLog(id, progressStr, task) + default: + progressStr, _ := json.Marshal(progress) + task.Log(string(progressStr)) + } + } + return nil +} + +func (c Client) BuildImageWithProcessAndOptions(task *task.Task, tar io.ReadCloser, options types.ImageBuildOptions) error { + out, err := c.cli.ImageBuild(context.Background(), tar, options) + if err != nil { + return err + } + defer out.Body.Close() + decoder := json.NewDecoder(out.Body) + for { + var progress map[string]interface{} + if err = decoder.Decode(&progress); err != nil { + if err == io.EOF { + break + } + return err + } + if msg, ok := progress["errorDetail"]; ok { + return fmt.Errorf("image build failed, err: %v", msg) + } + if msg, ok := progress["error"]; ok { + return fmt.Errorf("image build failed, err: %v", msg) + } + timeStr := time.Now().Format("2006/01/02 15:04:05") + status, _ := progress["status"].(string) + stream, _ := progress["stream"].(string) + if len(status) == 0 && len(stream) != 0 { + if stream != "\n" { + task.Log(stream) + } + continue + } + switch status { + case "Downloading", "Extracting": + id, _ := progress["id"].(string) + progressDetail, _ := progress["progressDetail"].(map[string]interface{}) + current, _ := progressDetail["current"].(float64) + progressStr := "" + total, ok := progressDetail["total"].(float64) + if ok { + progressStr = fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, (current/total)*100) + } else { + progressStr = fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, current) + } + + _ = setLog(id, progressStr, task) + case "Pull complete", "Download complete", "Verifying Checksum": + id, _ := progress["id"].(string) + progressStr := fmt.Sprintf("%s %s [%s] --- %.2f%%", timeStr, status, id, 100.0) + _ = setLog(id, progressStr, task) + default: + progressStr, _ := json.Marshal(progress) + task.Log(string(progressStr)) + } + } + return nil +} + func (c Client) PullImageWithProcess(task *task.Task, imageName string) error { return c.PullImageWithProcessAndOptions(task, imageName, image.PullOptions{}) } diff --git a/frontend/src/components/status/index.vue b/frontend/src/components/status/index.vue index 77e3366a9..799e3a1dc 100644 --- a/frontend/src/components/status/index.vue +++ b/frontend/src/components/status/index.vue @@ -55,7 +55,7 @@ const getType = (status: string) => { case 'enable': case 'done': case 'healthy': - case 'used': + case 'unused': case 'executing': return 'success'; case 'stopped':