Skip to content

Commit bd06553

Browse files
author
ssongliu
committed
feat: Add force image pull to container compose editing
1 parent 5db2ccb commit bd06553

5 files changed

Lines changed: 97 additions & 42 deletions

File tree

agent/app/dto/container.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ type ComposeCreate struct {
279279
Path string `json:"path"`
280280
Template uint `json:"template"`
281281
Env string `json:"env"`
282-
PullImage *bool `json:"pullImage,omitempty"`
282+
ForcePull bool `json:"forcePull"`
283283
}
284284
type ComposeOperation struct {
285285
Name string `json:"name" validate:"required"`
@@ -289,11 +289,13 @@ type ComposeOperation struct {
289289
Force bool `json:"force"`
290290
}
291291
type ComposeUpdate struct {
292+
TaskID string `json:"taskID"`
292293
Name string `json:"name" validate:"required"`
293294
Path string `json:"path" validate:"required"`
294295
DetailPath string `json:"detailPath"`
295296
Content string `json:"content" validate:"required"`
296297
Env string `json:"env"`
298+
ForcePull bool `json:"forcePull"`
297299
}
298300
type ComposeLogClean struct {
299301
Name string `json:"name" validate:"required"`

agent/app/service/container_compose.go

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,9 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
203203
if err := newComposeEnv(req.Path, req.Env); err != nil {
204204
return err
205205
}
206-
pullImages := true
207-
if req.PullImage != nil {
208-
pullImages = *req.PullImage
209-
}
210206
go func() {
211207
taskItem.AddSubTask(i18n.GetMsgByKey("ComposeCreate"), func(t *task.Task) error {
212-
err := compose.UpWithTask(req.Path, t, pullImages)
208+
err := compose.UpWithTask(req.Path, t, req.ForcePull)
213209
t.LogWithStatus(i18n.GetMsgByKey("ComposeCreate"), err)
214210
if err != nil {
215211
_, _ = compose.Down(req.Path)
@@ -262,31 +258,43 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
262258
if cmd.CheckIllegal(req.Name, req.Path) {
263259
return buserr.New("ErrCmdIllegal")
264260
}
265-
oldFile, err := os.ReadFile(req.DetailPath)
266-
if err != nil {
267-
return fmt.Errorf("load file with path %s failed, %v", req.DetailPath, err)
268-
}
269-
file, err := os.OpenFile(req.DetailPath, os.O_WRONLY|os.O_TRUNC, 0640)
261+
taskItem, err := task.NewTaskWithOps(req.Name, task.TaskUpdate, task.TaskScopeCompose, req.TaskID, 1)
270262
if err != nil {
263+
global.LOG.Errorf("new task for update compose failed, err: %v", err)
271264
return err
272265
}
273-
defer file.Close()
274-
write := bufio.NewWriter(file)
275-
_, _ = write.WriteString(req.Content)
276-
write.Flush()
266+
go func() {
267+
taskItem.AddSubTask(i18n.GetMsgByKey("TaskUpdate"), func(t *task.Task) error {
268+
oldFile, err := os.ReadFile(req.DetailPath)
269+
if err != nil {
270+
return fmt.Errorf("load file with path %s failed, %v", req.DetailPath, err)
271+
}
272+
file, err := os.OpenFile(req.DetailPath, os.O_WRONLY|os.O_TRUNC, 0640)
273+
if err != nil {
274+
return err
275+
}
276+
defer file.Close()
277+
write := bufio.NewWriter(file)
278+
_, _ = write.WriteString(req.Content)
279+
write.Flush()
277280

278-
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.DetailPath)
279-
if err := newComposeEnv(req.DetailPath, req.Env); err != nil {
280-
return err
281-
}
281+
global.LOG.Infof("docker-compose.yml %s has been replaced, now start to docker-compose restart", req.DetailPath)
282+
if err := newComposeEnv(req.DetailPath, req.Env); err != nil {
283+
return err
284+
}
282285

283-
if stdout, err := compose.Up(req.Path); err != nil {
284-
global.LOG.Errorf("update failed when handle compose up, std: %s, err: %s, now try to recreate the old compose file", stdout, err)
285-
if err := recreateCompose(string(oldFile), req.Path); err != nil {
286-
return fmt.Errorf("update failed and recreate old compose file also failed, err: %v", err)
287-
}
288-
return fmt.Errorf("update failed when handle compose up, std: %v, err: %s", stdout, err)
289-
}
286+
if stdout, err := compose.UpWithForcePull(req.Path, req.ForcePull); err != nil {
287+
global.LOG.Errorf("update failed when handle compose up, std: %s, err: %s, now try to recreate the old compose file", stdout, err)
288+
if err := recreateCompose(string(oldFile), req.Path); err != nil {
289+
return fmt.Errorf("update failed and recreate old compose file also failed, err: %v", err)
290+
}
291+
return fmt.Errorf("update failed when handle compose up, std: %v, err: %s", stdout, err)
292+
}
293+
294+
return nil
295+
}, nil)
296+
_ = taskItem.Execute()
297+
}()
290298

291299
return nil
292300
}

agent/utils/compose/compose.go

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,24 @@ func Up(filePath string) (string, error) {
3636
return cmd.NewCommandMgr(cmd.WithTimeout(20*time.Minute)).RunWithStdoutBashCf("%s %s up -d", global.CONF.DockerConfig.Command, loadFiles(filePath))
3737
}
3838

39-
func UpWithTask(filePath string, task *task.Task, pullImages bool) error {
40-
if !pullImages {
41-
return cmd.NewCommandMgr(cmd.WithTask(*task)).RunBashCf("%s %s up -d", global.CONF.DockerConfig.Command, loadFiles(filePath))
39+
func UpWithForcePull(filePath string, forcePull bool) (string, error) {
40+
if err := checkCmd(); err != nil {
41+
return "", err
42+
}
43+
if err := pullComposeImages(filePath, forcePull, nil); err != nil {
44+
return "", err
45+
}
46+
return cmd.NewCommandMgr(cmd.WithTimeout(20*time.Minute)).RunWithStdoutBashCf("%s %s up -d", global.CONF.DockerConfig.Command, loadFiles(filePath))
47+
}
48+
49+
func UpWithTask(filePath string, task *task.Task, forcePull bool) error {
50+
if err := pullComposeImages(filePath, forcePull, task); err != nil {
51+
return err
4252
}
53+
return cmd.NewCommandMgr(cmd.WithTask(*task)).RunBashCf("%s %s up -d", global.CONF.DockerConfig.Command, loadFiles(filePath))
54+
}
55+
56+
func pullComposeImages(filePath string, forcePull bool, task *task.Task) error {
4357
content, err := os.ReadFile(filePath)
4458
if err != nil {
4559
return err
@@ -57,11 +71,28 @@ func UpWithTask(filePath string, task *task.Task, pullImages bool) error {
5771
if err != nil {
5872
return err
5973
}
60-
errMsg := ""
6174
for _, image := range images {
62-
task.Log(i18n.GetWithName("PullImageStart", image))
63-
if err = dockerCLi.PullImageWithProcess(task, image); err != nil {
64-
errOur := err.Error()
75+
if !forcePull {
76+
if exist, _ := dockerCLi.ImageExists(image); exist {
77+
if task != nil {
78+
task.Log(i18n.GetMsgByKey("UseExistImage"))
79+
}
80+
continue
81+
}
82+
}
83+
84+
if task != nil {
85+
task.Log(i18n.GetWithName("PullImageStart", image))
86+
}
87+
pullErr := error(nil)
88+
if task != nil {
89+
pullErr = dockerCLi.PullImageWithProcess(task, image)
90+
} else {
91+
pullErr = docker.PullImage(image)
92+
}
93+
if pullErr != nil {
94+
errMsg := ""
95+
errOur := pullErr.Error()
6596
if errOur != "" {
6697
if strings.Contains(errOur, "no such host") {
6798
errMsg = i18n.GetMsgByKey("ErrNoSuchHost") + ":"
@@ -72,18 +103,21 @@ func UpWithTask(filePath string, task *task.Task, pullImages bool) error {
72103
}
73104
message := errMsg + errOur
74105
installErr := errors.New(message)
75-
task.LogFailedWithErr(i18n.GetMsgByKey("PullImage"), installErr)
106+
if task != nil {
107+
task.LogFailedWithErr(i18n.GetMsgByKey("PullImage"), installErr)
108+
}
76109
if exist, _ := dockerCLi.ImageExists(image); !exist {
77110
return installErr
78-
} else {
111+
}
112+
if task != nil {
79113
task.Log(i18n.GetMsgByKey("UseExistImage"))
80114
}
81-
} else {
115+
} else if task != nil {
82116
task.Log(i18n.GetMsgByKey("PullImageSuccess"))
83117
}
84118
}
85119

86-
return cmd.NewCommandMgr(cmd.WithTask(*task)).RunBashCf("%s %s up -d", global.CONF.DockerConfig.Command, loadFiles(filePath))
120+
return nil
87121
}
88122

89123
func Down(filePath string) (string, error) {

frontend/src/api/interface/container.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ export namespace Container {
329329
path: string;
330330
template: number;
331331
env: string;
332-
pullImage?: boolean;
332+
forcePull: boolean;
333333
}
334334
export interface ComposeOperation {
335335
name: string;
@@ -339,10 +339,12 @@ export namespace Container {
339339
force: boolean;
340340
}
341341
export interface ComposeUpdate {
342+
taskID: string;
342343
name: string;
343344
path: string;
344345
content: string;
345346
env: string;
347+
forcePull: boolean;
346348
createdBy: string;
347349
}
348350

frontend/src/views/container/compose/index.vue

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,10 @@
257257
<span v-if="currentCompose.createdBy === 'Apps'" class="input-help">
258258
{{ $t('container.composeEnvHelper2') }}
259259
</span>
260+
<div class="mt-2">
261+
<el-checkbox v-model="form.forcePull" :label="$t('container.forcePull')" />
262+
<span class="input-help">{{ $t('container.forcePullHelper') }}</span>
263+
</div>
260264

261265
<el-button type="primary" class="mt-2" @click="onSubmitEdit">
262266
{{ $t('commons.button.save') }}
@@ -336,8 +340,8 @@
336340
<el-input placeholder="key=value" type="textarea" :rows="3" v-model="form.env" />
337341
<span class="envTitle">{{ $t('commons.button.set') }}</span>
338342
<el-form-item>
339-
<el-checkbox v-model="form.pullImage" :label="$t('app.pullImage')" />
340-
<span class="input-help">{{ $t('app.pullImageHelper') }}</span>
343+
<el-checkbox v-model="form.forcePull" :label="$t('container.forcePull')" />
344+
<span class="input-help">{{ $t('container.forcePullHelper') }}</span>
341345
</el-form-item>
342346
</el-form>
343347

@@ -432,7 +436,7 @@ const form = reactive({
432436
file: '',
433437
template: null as number,
434438
env: '',
435-
pullImage: true,
439+
forcePull: false,
436440
});
437441
const rules = reactive({
438442
name: [Rules.requiredInput, Rules.composeName],
@@ -523,6 +527,7 @@ const loadDetail = async (row: Container.ComposeInfo, withRefresh: boolean) => {
523527
if (currentCompose.value?.name === row.name && withRefresh !== true) {
524528
return;
525529
}
530+
form.forcePull = false;
526531
isOnCreate.value = false;
527532
detailLoading.value = true;
528533
currentCompose.value = row;
@@ -562,7 +567,7 @@ const onOpenDialog = async () => {
562567
form.file = '';
563568
form.template = null;
564569
form.env = '';
565-
form.pullImage = true;
570+
form.forcePull = false;
566571
loadPath();
567572
loadTemplates();
568573
};
@@ -683,18 +688,22 @@ const loadSize = async (row: any) => {
683688
};
684689
685690
const onSubmitEdit = async () => {
691+
const taskID = newUUID();
686692
const param = {
693+
taskID: taskID,
687694
name: currentCompose.value.name,
688695
path: currentCompose.value.path,
689696
detailPath: currentYamlPath.value,
690697
content: composeContent.value,
691698
createdBy: currentCompose.value.createdBy,
692699
env: env.value || '',
700+
forcePull: form.forcePull,
693701
};
694702
loading.value = true;
695703
await composeUpdate(param)
696704
.then(async () => {
697705
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
706+
openTaskLog(taskID);
698707
await search();
699708
if (currentCompose.value) {
700709
const updated = data.value.find((item) => item.name === currentCompose.value.name);

0 commit comments

Comments
 (0)