feat: Implemented (un)install,start/stop flow and fixed actions flow
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
package containers
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/docker"
|
||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/logger"
|
||||
"git.dcntrlized.org/Dcntrlized/Maestro/lib/types"
|
||||
composetypes "github.com/compose-spec/compose-go/v2/types"
|
||||
"github.com/docker/compose/v2/pkg/api"
|
||||
)
|
||||
|
||||
// StartContainer creates and starts the service containers defined in the
|
||||
// service's docker-compose.yaml.
|
||||
func StartContainer(ctx context.Context, item types.RegistryContainer) error {
|
||||
dc, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize docker client: %w", err)
|
||||
}
|
||||
defer dc.Close()
|
||||
|
||||
serviceName := resolveServiceName(ctx, dc, item.Name)
|
||||
project, err := loadComposeProject(ctx, serviceName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// The compose file may reference the image by a short name (e.g.
|
||||
// "testservice") while install pulled it under its full registry reference.
|
||||
// Make sure those short names exist so Up() can find them.
|
||||
installedImage := item.Image
|
||||
if installedImage == "" {
|
||||
if dir, dirErr := getContainerDataDir(serviceName); dirErr == nil {
|
||||
if metadata, metaErr := readInstalledMetadata(dir); metaErr == nil {
|
||||
installedImage = metadata.Image
|
||||
}
|
||||
}
|
||||
}
|
||||
ensureServiceImages(ctx, dc, project, installedImage)
|
||||
|
||||
composeService, err := newComposeService(dc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Info("Starting service %s...", serviceName)
|
||||
err = composeService.Up(ctx, project, api.UpOptions{
|
||||
Create: api.CreateOptions{
|
||||
Recreate: api.RecreateDiverged,
|
||||
AssumeYes: true,
|
||||
},
|
||||
Start: api.StartOptions{},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to start service %s: %w", serviceName, err)
|
||||
}
|
||||
|
||||
logger.Info("Successfully started service: %s", serviceName)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ensureServiceImages makes sure every image referenced by the compose project
|
||||
// exists locally. Registries install the image under its full reference (e.g.
|
||||
// git.../testservice:3.4) while the service's compose file often references it
|
||||
// by a short name (e.g. "testservice"); when the short name is missing locally
|
||||
// and its base name matches the installed image, it is tagged so start works.
|
||||
func ensureServiceImages(ctx context.Context, dc *docker.DockerClient, project *composetypes.Project, installedImage string) {
|
||||
if installedImage == "" {
|
||||
return
|
||||
}
|
||||
for name, s := range project.Services {
|
||||
ref := s.Image
|
||||
if ref == "" || ref == installedImage {
|
||||
continue
|
||||
}
|
||||
if imageExists(ctx, dc, ref) {
|
||||
continue
|
||||
}
|
||||
if baseImageName(ref) != baseImageName(installedImage) {
|
||||
continue
|
||||
}
|
||||
logger.Info("Tagging %s as %s for compose service %s", installedImage, ref, name)
|
||||
if err := dc.Client.ImageTag(ctx, installedImage, ref); err != nil {
|
||||
logger.Warn("Failed to tag %s as %s: %v", installedImage, ref, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// imageExists reports whether an image reference exists locally.
|
||||
func imageExists(ctx context.Context, dc *docker.DockerClient, ref string) bool {
|
||||
_, _, err := dc.Client.ImageInspectWithRaw(ctx, ref)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// baseImageName strips the registry/namespace and tag from an image reference,
|
||||
// returning the repository name (e.g. "testservice").
|
||||
func baseImageName(ref string) string {
|
||||
base := ref
|
||||
if i := strings.LastIndex(base, "/"); i >= 0 {
|
||||
base = base[i+1:]
|
||||
}
|
||||
if i := strings.LastIndex(base, ":"); i >= 0 {
|
||||
base = base[:i]
|
||||
}
|
||||
return base
|
||||
}
|
||||
Reference in New Issue
Block a user