Skip to content

Commit 5963e28

Browse files
authored
fix: Fix ollama model log exception (#8037)
1 parent 2dec061 commit 5963e28

File tree

25 files changed

+152
-79
lines changed

25 files changed

+152
-79
lines changed

agent/app/api/v2/ai.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func (b *BaseApi) CreateOllamaModel(c *gin.Context) {
2424
return
2525
}
2626

27-
if err := aiToolService.Create(req.Name); err != nil {
27+
if err := aiToolService.Create(req); err != nil {
2828
helper.BadRequest(c, err)
2929
return
3030
}
@@ -46,7 +46,7 @@ func (b *BaseApi) RecreateOllamaModel(c *gin.Context) {
4646
return
4747
}
4848

49-
if err := aiToolService.Recreate(req.Name); err != nil {
49+
if err := aiToolService.Recreate(req); err != nil {
5050
helper.BadRequest(c, err)
5151
return
5252
}

agent/app/dto/ai.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ type OllamaModelDropList struct {
2020
}
2121

2222
type OllamaModelName struct {
23-
Name string `json:"name"`
23+
Name string `json:"name"`
24+
TaskID string `json:"taskID"`
2425
}
2526

2627
type OllamaBindDomain struct {

agent/app/service/ai.go

Lines changed: 39 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,20 @@ package service
33
import (
44
"context"
55
"fmt"
6-
"io"
76
"os"
8-
"os/exec"
97
"path"
108
"strings"
9+
"time"
1110

1211
"github.com/1Panel-dev/1Panel/agent/app/dto"
1312
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
1413
"github.com/1Panel-dev/1Panel/agent/app/model"
1514
"github.com/1Panel-dev/1Panel/agent/app/repo"
15+
"github.com/1Panel-dev/1Panel/agent/app/task"
1616
"github.com/1Panel-dev/1Panel/agent/buserr"
1717
"github.com/1Panel-dev/1Panel/agent/constant"
1818
"github.com/1Panel-dev/1Panel/agent/global"
19+
"github.com/1Panel-dev/1Panel/agent/i18n"
1920
"github.com/1Panel-dev/1Panel/agent/utils/cmd"
2021
"github.com/1Panel-dev/1Panel/agent/utils/common"
2122
"github.com/jinzhu/copier"
@@ -25,9 +26,9 @@ type AIToolService struct{}
2526

2627
type IAIToolService interface {
2728
Search(search dto.SearchWithPage) (int64, []dto.OllamaModelInfo, error)
28-
Create(name string) error
29+
Create(req dto.OllamaModelName) error
2930
Close(name string) error
30-
Recreate(name string) error
31+
Recreate(req dto.OllamaModelName) error
3132
Delete(req dto.ForceDelete) error
3233
Sync() ([]dto.OllamaModelDropList, error)
3334
LoadDetail(name string) (string, error)
@@ -55,8 +56,8 @@ func (u *AIToolService) Search(req dto.SearchWithPage) (int64, []dto.OllamaModel
5556
if err := copier.Copy(&item, &itemModel); err != nil {
5657
return 0, nil, buserr.WithDetail("ErrStructTransform", err.Error(), nil)
5758
}
58-
logPath := path.Join(global.Dir.DataDir, "log", "AITools", itemModel.Name)
59-
if _, err := os.Stat(logPath); err == nil {
59+
taskModel, _ := taskRepo.GetFirst(taskRepo.WithResourceID(item.ID), repo.WithByType(task.TaskScopeAI))
60+
if len(taskModel.ID) != 0 {
6061
item.LogFileExist = true
6162
}
6263
dtoLists = append(dtoLists, item)
@@ -79,37 +80,46 @@ func (u *AIToolService) LoadDetail(name string) (string, error) {
7980
return stdout, err
8081
}
8182

82-
func (u *AIToolService) Create(name string) error {
83-
if cmd.CheckIllegal(name) {
83+
func (u *AIToolService) Create(req dto.OllamaModelName) error {
84+
if cmd.CheckIllegal(req.Name) {
8485
return buserr.New("ErrCmdIllegal")
8586
}
86-
modelInfo, _ := aiRepo.Get(repo.WithByName(name))
87+
modelInfo, _ := aiRepo.Get(repo.WithByName(req.Name))
8788
if modelInfo.ID != 0 {
8889
return buserr.New("ErrRecordExist")
8990
}
9091
containerName, err := LoadContainerName()
9192
if err != nil {
9293
return err
9394
}
94-
logItem := path.Join(global.Dir.DataDir, "log", "AITools", name)
95-
if _, err := os.Stat(path.Dir(logItem)); err != nil && os.IsNotExist(err) {
96-
if err = os.MkdirAll(path.Dir(logItem), os.ModePerm); err != nil {
97-
return err
98-
}
99-
}
10095
info := model.OllamaModel{
101-
Name: name,
96+
Name: req.Name,
10297
From: "local",
10398
Status: constant.StatusWaiting,
10499
}
105100
if err := aiRepo.Create(&info); err != nil {
106101
return err
107102
}
108-
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
103+
taskItem, err := task.NewTaskWithOps(fmt.Sprintf("ollama-model-%s", req.Name), task.TaskPull, task.TaskScopeAI, req.TaskID, info.ID)
109104
if err != nil {
105+
global.LOG.Errorf("new task for exec shell failed, err: %v", err)
110106
return err
111107
}
112-
go pullOllamaModel(file, containerName, info)
108+
go func() {
109+
taskItem.AddSubTask(i18n.GetWithName("OllamaModelPull", req.Name), func(t *task.Task) error {
110+
return cmd.ExecShellWithTask(taskItem, time.Hour, "docker", "exec", containerName, "ollama", "pull", info.Name)
111+
}, nil)
112+
taskItem.AddSubTask(i18n.GetWithName("OllamaModelSize", req.Name), func(t *task.Task) error {
113+
itemSize, err := loadModelSize(info.Name, containerName)
114+
if len(itemSize) != 0 {
115+
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize})
116+
} else {
117+
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
118+
}
119+
return nil
120+
}, nil)
121+
_ = taskItem.Execute()
122+
}()
113123
return nil
114124
}
115125

@@ -128,11 +138,11 @@ func (u *AIToolService) Close(name string) error {
128138
return nil
129139
}
130140

131-
func (u *AIToolService) Recreate(name string) error {
132-
if cmd.CheckIllegal(name) {
141+
func (u *AIToolService) Recreate(req dto.OllamaModelName) error {
142+
if cmd.CheckIllegal(req.Name) {
133143
return buserr.New("ErrCmdIllegal")
134144
}
135-
modelInfo, _ := aiRepo.Get(repo.WithByName(name))
145+
modelInfo, _ := aiRepo.Get(repo.WithByName(req.Name))
136146
if modelInfo.ID == 0 {
137147
return buserr.New("ErrRecordNotFound")
138148
}
@@ -143,17 +153,17 @@ func (u *AIToolService) Recreate(name string) error {
143153
if err := aiRepo.Update(modelInfo.ID, map[string]interface{}{"status": constant.StatusWaiting, "from": "local"}); err != nil {
144154
return err
145155
}
146-
logItem := path.Join(global.Dir.DataDir, "log", "AITools", name)
147-
if _, err := os.Stat(path.Dir(logItem)); err != nil && os.IsNotExist(err) {
148-
if err = os.MkdirAll(path.Dir(logItem), os.ModePerm); err != nil {
149-
return err
150-
}
151-
}
152-
file, err := os.OpenFile(logItem, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
156+
taskItem, err := task.NewTaskWithOps(fmt.Sprintf("ollama-model-%s", req.Name), task.TaskPull, task.TaskScopeAI, req.TaskID, modelInfo.ID)
153157
if err != nil {
158+
global.LOG.Errorf("new task for exec shell failed, err: %v", err)
154159
return err
155160
}
156-
go pullOllamaModel(file, containerName, modelInfo)
161+
go func() {
162+
taskItem.AddSubTask(i18n.GetWithName("OllamaModelPull", req.Name), func(t *task.Task) error {
163+
return cmd.ExecShellWithTask(taskItem, time.Hour, "docker", "exec", containerName, "ollama", "pull", req.Name)
164+
}, nil)
165+
_ = taskItem.Execute()
166+
}()
157167
return nil
158168
}
159169

@@ -354,22 +364,6 @@ func LoadContainerName() (string, error) {
354364
return ollamaBaseInfo.ContainerName, nil
355365
}
356366

357-
func pullOllamaModel(file *os.File, containerName string, info model.OllamaModel) {
358-
defer file.Close()
359-
cmd := exec.Command("docker", "exec", containerName, "ollama", "pull", info.Name)
360-
multiWriter := io.MultiWriter(os.Stdout, file)
361-
cmd.Stdout = multiWriter
362-
cmd.Stderr = multiWriter
363-
_ = cmd.Run()
364-
itemSize, err := loadModelSize(info.Name, containerName)
365-
if len(itemSize) != 0 {
366-
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusSuccess, "size": itemSize})
367-
} else {
368-
_ = aiRepo.Update(info.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
369-
}
370-
_, _ = file.WriteString("ollama pull completed!")
371-
}
372-
373367
func loadModelSize(name string, containerName string) (string, error) {
374368
stdout, err := cmd.Execf("docker exec %s ollama list | grep %s", containerName, name)
375369
if err != nil {

agent/app/service/cronjob_helper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ func (u *CronjobService) handleCurl(cronjob model.Cronjob, taskID string) error
139139
}
140140

141141
taskItem.AddSubTask(i18n.GetWithName("HandleShell", cronjob.Name), func(t *task.Task) error {
142-
if err := cmd.ExecShellWithTask(taskItem, 24*time.Hour, "bash", "-c", "curl", cronjob.URL); err != nil {
142+
if err := cmd.ExecShellWithTask(taskItem, 24*time.Hour, "curl", cronjob.URL); err != nil {
143143
return err
144144
}
145145
return nil

agent/app/service/firewall.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -610,11 +610,7 @@ func (u *FirewallService) updatePingStatus(enable string) error {
610610
}
611611

612612
func (u *FirewallService) addPortsBeforeStart(client firewall.FirewallClient) error {
613-
serverPort, err := settingRepo.Get(settingRepo.WithByKey("ServerPort"))
614-
if err != nil {
615-
return err
616-
}
617-
if err := client.Port(fireClient.FireInfo{Port: serverPort.Value, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
613+
if err := client.Port(fireClient.FireInfo{Port: global.CONF.Base.Port, Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {
618614
return err
619615
}
620616
if err := client.Port(fireClient.FireInfo{Port: "22", Protocol: "tcp", Strategy: "accept"}, "add"); err != nil {

agent/app/task/task.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ const (
6868

6969
const (
7070
TaskScopeWebsite = "Website"
71+
TaskScopeAI = "AI"
7172
TaskScopeApp = "App"
7273
TaskScopeRuntime = "Runtime"
7374
TaskScopeDatabase = "Database"

agent/constant/status.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package constant
22

33
const (
44
StatusRunning = "Running"
5+
StatusCanceled = "Canceled"
56
StatusDone = "Done"
67
StatusWaiting = "Waiting"
78
StatusSuccess = "Success"

agent/i18n/lang/zh.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ SubTask: "子任务"
312312
RuntimeExtension: "运行环境扩展"
313313
TaskIsExecuting: "任务正在运行"
314314

315+
# task - ai
316+
OllamaModelPull: "拉取 Ollama 模型 {{ .name }} "
317+
OllamaModelSize: "获取 Ollama 模型 {{ .name }} 大小 "
318+
315319
# task - snapshot
316320
Snapshot: "快照"
317321
SnapDBInfo: "写入 1Panel 数据库信息"

agent/init/hook/hook.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ func Init() {
1818
initGlobalData()
1919
handleCronjobStatus()
2020
handleSnapStatus()
21+
handleOllamaModelStatus()
2122

2223
loadLocalDir()
2324
}
@@ -82,6 +83,11 @@ func handleCronjobStatus() {
8283
}
8384
}
8485

86+
func handleOllamaModelStatus() {
87+
message := "the task was interrupted due to the restart of the 1panel service"
88+
_ = global.DB.Model(&model.OllamaModel{}).Where("status = ?", constant.StatusWaiting).Updates(map[string]interface{}{"status": constant.StatusCanceled, "message": message}).Error
89+
}
90+
8591
func handleCronJobAlert(cronjob *model.Cronjob) {
8692
pushAlert := dto.PushAlert{
8793
TaskName: cronjob.Name,

agent/utils/cmd/cmd.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,12 +146,27 @@ func ExecShell(outPath string, timeout time.Duration, name string, arg ...string
146146

147147
type CustomWriter struct {
148148
taskItem *task.Task
149+
buffer bytes.Buffer
149150
}
150151

151152
func (cw *CustomWriter) Write(p []byte) (n int, err error) {
152-
cw.taskItem.Log(string(p))
153+
cw.buffer.Write(p)
154+
lines := strings.Split(cw.buffer.String(), "\n")
155+
156+
for i := 0; i < len(lines)-1; i++ {
157+
cw.taskItem.Log(lines[i])
158+
}
159+
cw.buffer.Reset()
160+
cw.buffer.WriteString(lines[len(lines)-1])
161+
153162
return len(p), nil
154163
}
164+
func (cw *CustomWriter) Flush() {
165+
if cw.buffer.Len() > 0 {
166+
cw.taskItem.Log(cw.buffer.String())
167+
cw.buffer.Reset()
168+
}
169+
}
155170
func ExecShellWithTask(taskItem *task.Task, timeout time.Duration, name string, arg ...string) error {
156171
env := os.Environ()
157172
customWriter := &CustomWriter{taskItem: taskItem}
@@ -165,6 +180,7 @@ func ExecShellWithTask(taskItem *task.Task, timeout time.Duration, name string,
165180
done := make(chan error, 1)
166181
go func() {
167182
done <- cmd.Wait()
183+
customWriter.Flush()
168184
}()
169185
after := time.After(timeout)
170186
select {

0 commit comments

Comments
 (0)