Files
ThothII/tools/tht/internal/preflight/compose.go

61 lines
2.8 KiB
Go

package preflight
import (
"context"
"encoding/json"
"os"
"path/filepath"
"github.com/aritmolab/thothii/tools/tht/internal/config"
)
// CheckCompose resolves the distributed release plus authored overrides without starting services.
func CheckCompose(ctx context.Context, runner Runner, installation config.Installation, m Manifest, manifestPath, platform string) Report {
r := NewReport()
args := []string{"compose", "--project-directory", installation.ProjectDirectory, "--env-file", installation.EnvFile}
for _, name := range m.Compose {
args = append(args, "-f", filepath.Join(filepath.Dir(manifestPath), filepath.FromSlash(name)))
}
for _, path := range installation.Overrides {
if _, err := os.Stat(path); os.IsNotExist(err) {
// Only the two well-known distribution-owned transport overlays can be relocated.
name := "deploy/" + filepath.Base(path)
if path != filepath.Join(installation.ProjectDirectory, filepath.FromSlash(name)) || (name != "deploy/compose.git-https.yaml" && name != "deploy/compose.git-ssh.yaml") || m.Files[name] == "" {
r.Add("compose-assets", "error", "overrides", "Include the selected Git transport overlay in the verified release.")
return r
}
path = filepath.Join(filepath.Dir(manifestPath), filepath.FromSlash(name))
}
args = append(args, "-f", path)
}
args = append(args, "config", "--format", "json")
result, err := docker(ctx, runner, args...)
var effective struct {
Services map[string]struct {
Image string `json:"image"`
Build any `json:"build"`
Platform string `json:"platform"`
} `json:"services"`
}
if err != nil || json.Unmarshal([]byte(result.Stdout), &effective) != nil {
r.Add("compose-configuration", "error", "operator.env", "Correct the effective Compose configuration using the release assets and prepared environment; no raw output is logged.")
return r
}
roles := map[string]string{"core": "core", "catalog-migrate": "core", "workspace-maintenance": "core", "frontend": "frontend", "catalog-db": "catalog", "qdrant": "qdrant", "embedding": "embedding", "embedding-model-init": "embedding"}
for service, role := range roles {
entry, exists := effective.Services[service]
if !exists || entry.Build != nil || entry.Image != m.Images[role][platform] || (entry.Platform != "" && entry.Platform != platform) {
r.Add("compose-image-"+service, "error", "release.compose", "Each runtime and maintenance service must use its released immutable image without a source build.")
}
}
for service := range effective.Services {
if _, ok := roles[service]; !ok {
r.Add("compose-service", "error", "release.compose", "Additional services need an explicit release contract before execution.")
}
}
if r.OK {
r.Add("compose-configuration", "passed", "release.compose", "Effective Compose configuration uses the complete released image set.")
}
return r
}