Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/arduino-app-cli/app/restart.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func restartHandler(ctx context.Context, cfg config.Configuration, app app.Ardui
servicelocator.GetProvisioner(),
servicelocator.GetModelsIndex(),
servicelocator.GetBricksIndex(),
servicelocator.GetServicesIndex(),
app,
cfg,
servicelocator.GetStaticStore(),
Expand Down
1 change: 1 addition & 0 deletions cmd/arduino-app-cli/app/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ func startHandler(ctx context.Context, cfg config.Configuration, app app.Arduino
servicelocator.GetProvisioner(),
servicelocator.GetModelsIndex(),
servicelocator.GetBricksIndex(),
servicelocator.GetServicesIndex(),
app,
cfg,
servicelocator.GetStaticStore(),
Expand Down
2 changes: 2 additions & 0 deletions cmd/arduino-app-cli/daemon/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func NewDaemonCmd(cfg config.Configuration, version string) *cobra.Command {
servicelocator.GetProvisioner(),
servicelocator.GetModelsIndex(),
servicelocator.GetBricksIndex(),
servicelocator.GetServicesIndex(),
servicelocator.GetAppIDProvider(),
cfg,
servicelocator.GetStaticStore(),
Expand Down Expand Up @@ -121,6 +122,7 @@ func httpHandler(ctx context.Context, cfg config.Configuration, daemonPort, vers
servicelocator.GetStaticStore(),
servicelocator.GetModelsIndex(),
servicelocator.GetBricksIndex(),
servicelocator.GetServicesIndex(),
servicelocator.GetBrickService(),
servicelocator.GetAppIDProvider(),
servicelocator.GetPlatform(),
Expand Down
6 changes: 6 additions & 0 deletions cmd/arduino-app-cli/internal/servicelocator/servicelocator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import (
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
"github.com/arduino/arduino-app-cli/internal/orchestrator/modelsindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/servicesindex"
"github.com/arduino/arduino-app-cli/internal/platform"
"github.com/arduino/arduino-app-cli/internal/store"
)
Expand All @@ -52,6 +53,10 @@ var (
return f.Must(modelsindex.Load(GetStaticStore().GetAssetsFolder(), globalConfig.CustomModelsDir()))
})

GetServicesIndex = sync.OnceValue(func() *servicesindex.ServicesIndex {
return f.Must(servicesindex.Load(GetStaticStore().GetServicesFolder()))
})

GetProvisioner = sync.OnceValue(func() *orchestrator.Provision {
return f.Must(orchestrator.NewProvision(
GetDockerClient(),
Expand Down Expand Up @@ -91,6 +96,7 @@ var (
return bricks.NewService(
GetModelsIndex(),
GetBricksIndex(),
GetServicesIndex(),
)
})

Expand Down
4 changes: 3 additions & 1 deletion internal/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
"github.com/arduino/arduino-app-cli/internal/orchestrator/modelsindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/servicesindex"
"github.com/arduino/arduino-app-cli/internal/platform"
"github.com/arduino/arduino-app-cli/internal/store"
"github.com/arduino/arduino-app-cli/internal/update"
Expand All @@ -48,6 +49,7 @@ func NewHTTPRouter(
staticStore *store.StaticStore,
modelsIndex *modelsindex.ModelsIndex,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
brickService *bricks.Service,
idProvider *app.IDProvider,
platform platform.Platform,
Expand Down Expand Up @@ -83,7 +85,7 @@ func NewHTTPRouter(
mux.Handle("GET /v1/apps/{appID}", handlers.HandleAppDetails(dockerClient, bricksIndex, idProvider, cfg))
mux.Handle("PATCH /v1/apps/{appID}", handlers.HandleAppDetailsEdits(dockerClient, bricksIndex, idProvider, cfg))
mux.Handle("GET /v1/apps/{appID}/logs", handlers.HandleAppLogs(dockerClient, idProvider, bricksIndex))
mux.Handle("POST /v1/apps/{appID}/start", handlers.HandleAppStart(dockerClient, provisioner, modelsIndex, bricksIndex, idProvider, cfg, staticStore, platform))
mux.Handle("POST /v1/apps/{appID}/start", handlers.HandleAppStart(dockerClient, provisioner, modelsIndex, bricksIndex, servicesIndex, idProvider, cfg, staticStore, platform))
mux.Handle("POST /v1/apps/{appID}/stop", handlers.HandleAppStop(dockerClient, idProvider, platform))
mux.Handle("POST /v1/apps/{appID}/clone", handlers.HandleAppClone(dockerClient, idProvider, cfg))
mux.Handle("DELETE /v1/apps/{appID}", handlers.HandleAppDelete(dockerClient, idProvider, platform))
Expand Down
4 changes: 3 additions & 1 deletion internal/api/handlers/app_start.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
"github.com/arduino/arduino-app-cli/internal/orchestrator/modelsindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/servicesindex"
"github.com/arduino/arduino-app-cli/internal/platform"
"github.com/arduino/arduino-app-cli/internal/render"
"github.com/arduino/arduino-app-cli/internal/store"
Expand All @@ -39,6 +40,7 @@ func HandleAppStart(
provisioner *orchestrator.Provision,
modelsIndex *modelsindex.ModelsIndex,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
idProvider *app.IDProvider,
cfg config.Configuration,
staticStore *store.StaticStore,
Expand Down Expand Up @@ -73,7 +75,7 @@ func HandleAppStart(
type log struct {
Message string `json:"message"`
}
for item := range orchestrator.StartApp(r.Context(), dockerCli, provisioner, modelsIndex, bricksIndex, app, cfg, staticStore, platform) {
for item := range orchestrator.StartApp(r.Context(), dockerCli, provisioner, modelsIndex, bricksIndex, servicesIndex, app, cfg, staticStore, platform) {
switch item.GetType() {
case orchestrator.ProgressType:
sseStream.Send(render.SSEEvent{Type: "progress", Data: progress(*item.GetProgress())})
Expand Down
12 changes: 8 additions & 4 deletions internal/orchestrator/bricks/bricks.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import (
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
"github.com/arduino/arduino-app-cli/internal/orchestrator/modelsindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/servicesindex"
)

var (
Expand All @@ -39,17 +40,20 @@ var (
)

type Service struct {
modelsIndex *modelsindex.ModelsIndex
bricksIndex *bricksindex.BricksIndex
modelsIndex *modelsindex.ModelsIndex
bricksIndex *bricksindex.BricksIndex
servicesIndex *servicesindex.ServicesIndex
}

func NewService(
modelsIndex *modelsindex.ModelsIndex,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
) *Service {
return &Service{
modelsIndex: modelsIndex,
bricksIndex: bricksIndex,
modelsIndex: modelsIndex,
bricksIndex: bricksIndex,
servicesIndex: servicesIndex,
}
}

Expand Down
12 changes: 6 additions & 6 deletions internal/orchestrator/bricks/bricks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import (
func TestBrickCreate(t *testing.T) {
bricksIndex, err := bricksindex.Load(paths.New("testdata"))
require.Nil(t, err)
brickService := NewService(nil, bricksIndex)
brickService := NewService(nil, bricksIndex, nil)

t.Run("fails if brick id does not exist", func(t *testing.T) {
err = brickService.BrickCreate(BrickCreateUpdateRequest{ID: "not-existing-id"}, f.Must(app.Load(paths.New("testdata/dummy-app"))))
Expand Down Expand Up @@ -105,7 +105,7 @@ func TestBrickCreate(t *testing.T) {
require.Nil(t, err)
bricksIndex, err := bricksindex.Load(paths.New("testdata"))
require.Nil(t, err)
brickService := NewService(nil, bricksIndex)
brickService := NewService(nil, bricksIndex, nil)

deviceID := "this-is-a-device-id"
secret := "this-is-a-secret"
Expand All @@ -132,7 +132,7 @@ func TestBrickCreate(t *testing.T) {
func TestUpdateBrick(t *testing.T) {
bricksIndex, err := bricksindex.Load(paths.New("testdata"))
require.Nil(t, err)
brickService := NewService(nil, bricksIndex)
brickService := NewService(nil, bricksIndex, nil)

t.Run("fails if brick id does not exist into brick index", func(t *testing.T) {
err = brickService.BrickUpdate(BrickCreateUpdateRequest{ID: "not-existing-id"}, f.Must(app.Load(paths.New("testdata/dummy-app"))))
Expand Down Expand Up @@ -192,7 +192,7 @@ func TestUpdateBrick(t *testing.T) {
require.Nil(t, paths.New("testdata/dummy-app").CopyDirTo(tempDummyApp))
bricksIndex, err := bricksindex.Load(paths.New("testdata"))
require.Nil(t, err)
brickService := NewService(nil, bricksIndex)
brickService := NewService(nil, bricksIndex, nil)

deviceID := "updated-device-id"
secret := "updated-secret"
Expand Down Expand Up @@ -221,7 +221,7 @@ func TestUpdateBrick(t *testing.T) {
require.Nil(t, paths.New("testdata/dummy-app-for-update").CopyDirTo(tempDummyApp))
bricksIndex, err := bricksindex.Load(paths.New("testdata"))
require.Nil(t, err)
brickService := NewService(nil, bricksIndex)
brickService := NewService(nil, bricksIndex, nil)

secret := "updated-the-secret"
req := BrickCreateUpdateRequest{
Expand Down Expand Up @@ -251,7 +251,7 @@ func TestUpdateBrick(t *testing.T) {
require.NoError(t, err)
modelsIndex, err := modelsindex.Load(paths.New("testdata"), paths.New("not_exixsting_path"))
require.NoError(t, err)
brickService := NewService(modelsIndex, bricksIndex)
brickService := NewService(modelsIndex, bricksIndex, nil)

modelPath := "/home/arduino/.arduino-bricks/ei-model-123-1/model.eim"
modelId := "ei-model-123-1"
Expand Down
1 change: 1 addition & 0 deletions internal/orchestrator/bricksindex/bricks_index.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ type Brick struct {
ModelName string `yaml:"model_name,omitempty"`
MountDevicesIntoContainer bool `yaml:"mount_devices_into_container,omitempty"`
RequiredDevices []peripherals.DeviceClass `yaml:"required_devices,omitempty"`
RequiresServices []string `yaml:"requires_services,omitempty"`

Source string `yaml:"-"`

Expand Down
10 changes: 7 additions & 3 deletions internal/orchestrator/orchestrator.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import (
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
"github.com/arduino/arduino-app-cli/internal/orchestrator/modelsindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/peripherals"
"github.com/arduino/arduino-app-cli/internal/orchestrator/servicesindex"
"github.com/arduino/arduino-app-cli/internal/platform"
"github.com/arduino/arduino-app-cli/internal/store"
)
Expand Down Expand Up @@ -113,6 +114,7 @@ func StartApp(
provisioner *Provision,
modelsIndex *modelsindex.ModelsIndex,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
appToStart app.ArduinoApp,
cfg config.Configuration,
staticStore *store.StaticStore,
Expand Down Expand Up @@ -198,7 +200,7 @@ func StartApp(
return
}

if err := provisioner.App(ctx, bricksIndex, &appToStart, cfg, envs, platform, devices); err != nil {
if err := provisioner.App(ctx, bricksIndex, servicesIndex, &appToStart, cfg, envs, platform, devices); err != nil {
yield(StreamMessage{error: err})
return
}
Expand Down Expand Up @@ -432,6 +434,7 @@ func RestartApp(
provisioner *Provision,
modelsIndex *modelsindex.ModelsIndex,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
appToStart app.ArduinoApp,
cfg config.Configuration,
staticStore *store.StaticStore,
Expand Down Expand Up @@ -462,7 +465,7 @@ func RestartApp(
}
}
}
startStream := StartApp(ctx, docker, provisioner, modelsIndex, bricksIndex, appToStart, cfg, staticStore, platform)
startStream := StartApp(ctx, docker, provisioner, modelsIndex, bricksIndex, servicesIndex, appToStart, cfg, staticStore, platform)
startStream(yield)
}
}
Expand All @@ -473,6 +476,7 @@ func StartDefaultApp(
provisioner *Provision,
modelsIndex *modelsindex.ModelsIndex,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
idProvider *app.IDProvider,
cfg config.Configuration,
staticStore *store.StaticStore,
Expand All @@ -496,7 +500,7 @@ func StartDefaultApp(
}

// TODO: we need to stop all other running app before starting the default app.
for msg := range StartApp(ctx, docker, provisioner, modelsIndex, bricksIndex, *app, cfg, staticStore, platform) {
for msg := range StartApp(ctx, docker, provisioner, modelsIndex, bricksIndex, servicesIndex, *app, cfg, staticStore, platform) {
if msg.IsError() {
return fmt.Errorf("failed to start app: %w", msg.GetError())
}
Expand Down
33 changes: 32 additions & 1 deletion internal/orchestrator/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import (
"github.com/arduino/arduino-app-cli/internal/orchestrator/bricksindex"
"github.com/arduino/arduino-app-cli/internal/orchestrator/config"
"github.com/arduino/arduino-app-cli/internal/orchestrator/peripherals"
"github.com/arduino/arduino-app-cli/internal/orchestrator/servicesindex"
"github.com/arduino/arduino-app-cli/internal/platform"
)

Expand Down Expand Up @@ -120,6 +121,7 @@ func NewProvision(
func (p *Provision) App(
ctx context.Context,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
arduinoApp *app.ArduinoApp,
cfg config.Configuration,
mapped_env map[string]string,
Expand All @@ -138,7 +140,7 @@ func (p *Provision) App(

bricksIndex = bricksIndex.WithAppBricks(arduinoApp.LocalBricks)

return generateMainComposeFile(arduinoApp, bricksIndex, p.pythonImage, cfg, mapped_env, platform, devices)
return generateMainComposeFile(arduinoApp, bricksIndex, servicesIndex, p.pythonImage, cfg, mapped_env, platform, devices)
}

func (p *Provision) init(
Expand Down Expand Up @@ -216,6 +218,7 @@ const (
func generateMainComposeFile(
app *app.ArduinoApp,
bricksIndex *bricksindex.BricksIndex,
servicesIndex *servicesindex.ServicesIndex,
pythonImage string,
cfg config.Configuration,
envs helpers.EnvVars,
Expand All @@ -229,6 +232,8 @@ func generateMainComposeFile(
ports[fmt.Sprintf("%d:%d", p, p)] = struct{}{}
}

requiredServices := make(map[string]servicesindex.Service)

var composeFiles paths.PathList
services := make([]serviceInfo, 0, len(app.Descriptor.Bricks))
for _, brick := range app.Descriptor.Bricks {
Expand All @@ -243,6 +248,16 @@ func generateMainComposeFile(
ports[fmt.Sprintf("%s:%s", p, p)] = struct{}{}
}

// 2. Retrieve the required singleton services
for _, id := range idxBrick.RequiresServices {
idxService, found := servicesIndex.FindServiceByID(id)
if !found {
slog.Error("service required by brick not found in services index", slog.String("service_id", id), slog.String("brick_id", brick.ID))
continue
}
requiredServices[id] = *idxService
}

// The following code is needed only if the brick requires a container.
// In case it doesn't we just skip to the next one.
if !idxBrick.RequireContainer {
Expand Down Expand Up @@ -279,6 +294,22 @@ func generateMainComposeFile(
slog.Warn("The 'required_devices' field is deprecated. Please move requirements to the specific 'bricks' section.")
}

// Add the singleton services compose files to the list of the brick compose files
for _, s := range requiredServices {
serviceCompose, ok := s.GetComposeFile()
if !ok {
slog.Error("service compose not found", slog.String("service_id", s.ServiceID))
continue
}
svcs, err := extractServicesFromComposeFile(serviceCompose)
if err != nil {
slog.Error("loading service_compose", slog.String("service_id", s.ServiceID), slog.String("path", serviceCompose.String()), slog.Any("error", err))
continue
}
composeFiles.AddIfMissing(serviceCompose)
services = append(services, svcs...)
}

// Create a single docker-mainCompose that includes all the required services
mainComposeFile := app.AppComposeFilePath()
// If required, create an override compose file for devices
Expand Down
Loading
Loading