Skip to content

Commit 6ca9d79

Browse files
Enable always pull container by default (#546)
1 parent c09f117 commit 6ca9d79

File tree

2 files changed

+69
-23
lines changed

2 files changed

+69
-23
lines changed

cmd/arduino-app-cli/daemon/daemon.go

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -21,29 +21,12 @@ import (
2121
)
2222

2323
func NewDaemonCmd(cfg config.Configuration, version string) *cobra.Command {
24-
var autoPull bool
2524
daemonCmd := &cobra.Command{
2625
Use: "daemon",
2726
Short: "Run an HTTP server to expose arduino-app-cli functionality thorough REST API",
2827
Run: func(cmd *cobra.Command, args []string) {
2928
daemonPort, _ := cmd.Flags().GetString("port")
3029

31-
if autoPull {
32-
go func() {
33-
slog.Info("Auto-pull enabled, starting background process...")
34-
err := orchestrator.SystemInit(
35-
cmd.Context(),
36-
servicelocator.GetUsedPythonImageTag(),
37-
servicelocator.GetStaticStore(),
38-
)
39-
if err != nil {
40-
slog.Error("Auto-pull process failed", slog.String("error", err.Error()))
41-
} else {
42-
slog.Info("Auto-pull process completed.")
43-
}
44-
}()
45-
}
46-
4730
// start the default app in the background
4831
go func() {
4932
slog.Info("Starting default app")
@@ -59,15 +42,27 @@ func NewDaemonCmd(cfg config.Configuration, version string) *cobra.Command {
5942
)
6043
if err != nil {
6144
slog.Error("Failed to start default app", slog.String("error", err.Error()))
45+
} else {
46+
slog.Info("Default app started")
47+
}
48+
49+
slog.Info("Try to pull latest docker images in background...")
50+
err = orchestrator.SystemInit(
51+
cmd.Context(),
52+
servicelocator.GetUsedPythonImageTag(),
53+
servicelocator.GetStaticStore(),
54+
)
55+
if err != nil {
56+
slog.Error("Auto-pull process failed", slog.String("error", err.Error()))
57+
} else {
58+
slog.Info("Auto-pull process completed.")
6259
}
63-
slog.Info("Default app started")
6460
}()
6561

6662
httpHandler(cmd.Context(), cfg, daemonPort, version)
6763
},
6864
}
6965
daemonCmd.Flags().String("port", "8080", "The TCP port the daemon will listen to")
70-
daemonCmd.Flags().BoolVarP(&autoPull, "auto-pull", "p", false, "Enable auto-pull of all app images on startup")
7166
return daemonCmd
7267
}
7368

internal/orchestrator/system.go

Lines changed: 55 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package orchestrator
22

33
import (
4+
"bytes"
45
"context"
6+
"encoding/json"
57
"os"
8+
"slices"
69
"strings"
710

811
"github.com/arduino/go-paths-helper"
@@ -16,22 +19,31 @@ import (
1619

1720
// SystemInit pulls necessary Docker images.
1821
func SystemInit(ctx context.Context, pythonImageTag string, staticStore *store.StaticStore) error {
19-
preInstallContainer := []string{
22+
containersToPreinstall := []string{
2023
"ghcr.io/bcmi-labs/arduino/appslab-python-apps-base:" + pythonImageTag,
2124
}
2225
additionalContainers, err := parseAllModelsRunnerImageTag(staticStore)
2326
if err != nil {
2427
return err
2528
}
26-
preInstallContainer = append(preInstallContainer, additionalContainers...)
29+
containersToPreinstall = append(containersToPreinstall, additionalContainers...)
30+
31+
pulledImages, err := listImagesAlreadyPulled(ctx)
32+
if err != nil {
33+
return err
34+
}
35+
36+
// Filter out containers alredy pulled
37+
containersToPreinstall = slices.DeleteFunc(containersToPreinstall, func(v string) bool {
38+
return slices.Contains(pulledImages, v)
39+
})
2740

2841
stdout, _, err := feedback.DirectStreams()
2942
if err != nil {
3043
feedback.Fatal(err.Error(), feedback.ErrBadArgument)
3144
return nil
3245
}
33-
34-
for _, container := range preInstallContainer {
46+
for _, container := range containersToPreinstall {
3547
cmd, err := paths.NewProcess(nil, "docker", "pull", container)
3648
if err != nil {
3749
return err
@@ -45,6 +57,45 @@ func SystemInit(ctx context.Context, pythonImageTag string, staticStore *store.S
4557
return nil
4658
}
4759

60+
// listImagesAlreadyPulled
61+
func listImagesAlreadyPulled(ctx context.Context) ([]string, error) {
62+
cmd, err := paths.NewProcess(nil,
63+
"docker", "images", "--format", "json",
64+
"-f", "reference=ghcr.io/bcmi-labs/arduino/*",
65+
"-f", "reference=public.ecr.aws/*",
66+
)
67+
if err != nil {
68+
return nil, err
69+
}
70+
71+
// Capture the output to check if the image exists
72+
stdout, _, err := cmd.RunAndCaptureOutput(ctx)
73+
if err != nil {
74+
return nil, err
75+
}
76+
77+
type dockerImage struct {
78+
Repository string `json:"Repository"`
79+
Tag string `json:"Tag"`
80+
}
81+
var resp dockerImage
82+
result := []string{}
83+
for img := range bytes.Lines(stdout) {
84+
if len(img) == 0 {
85+
continue
86+
}
87+
if err := json.Unmarshal(img, &resp); err != nil {
88+
return nil, err
89+
}
90+
if resp.Tag == "<none>" {
91+
continue
92+
}
93+
result = append(result, resp.Repository+":"+resp.Tag)
94+
}
95+
96+
return result, nil
97+
}
98+
4899
func parseAllModelsRunnerImageTag(staticStore *store.StaticStore) ([]string, error) {
49100
composePath := staticStore.GetComposeFolder()
50101
brickNamespace := "arduino"

0 commit comments

Comments
 (0)