From ec4598f81f31dde0c9fdfd7518bff0f53317b98e Mon Sep 17 00:00:00 2001 From: Christian Kellner Date: Thu, 21 Jul 2022 17:22:03 +0200 Subject: [PATCH] weldr: use worker job to resolve container The main reason is that there should be only one place where the container resolution is happening, which is the worker, so that we only have one central place to configure aspects of it, like container credentials. --- internal/weldr/api.go | 62 ++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/internal/weldr/api.go b/internal/weldr/api.go index fd7ee122f..4e23f9db1 100644 --- a/internal/weldr/api.go +++ b/internal/weldr/api.go @@ -6,6 +6,7 @@ import ( "context" "crypto/rand" "encoding/json" + "errors" errors_package "errors" "fmt" "io" @@ -2165,13 +2166,66 @@ func (api *API) depsolveBlueprintForImageType(bp blueprint.Blueprint, options di } func (api *API) resolveContainersForImageType(bp blueprint.Blueprint, imageType distro.ImageType) ([]container.Spec, error) { - resolver := container.NewResolver(imageType.Arch().Name()) - for _, c := range bp.Containers { - resolver.Add(c.Source, c.Name, c.TLSVerify) + specs := make([]container.Spec, len(bp.Containers)) + + // shortcut + if len(bp.Containers) == 0 { + return specs, nil } - return resolver.Finish() + job := worker.ContainerResolveJob{ + Arch: api.archName, + Specs: make([]worker.ContainerSpec, len(bp.Containers)), + } + + for i, c := range bp.Containers { + job.Specs[i] = worker.ContainerSpec{ + Source: c.Source, + Name: c.Name, + TLSVerify: c.TLSVerify, + } + } + + jobId, err := api.workers.EnqueueContainerResolveJob(&job, "") + + if err != nil { + return specs, err + } + + var result worker.ContainerResolveJobResult + + for { + status, _, err := api.workers.ContainerResolveJobStatus(jobId, &result) + + if err != nil { + return specs, err + } + + if result.JobError != nil { + return specs, errors.New(result.JobError.Reason) + } else if status.Canceled { + return specs, fmt.Errorf("Failed to resolve containers: job cancelled") + } else if !status.Finished.IsZero() { + break + } + + time.Sleep(time.Millisecond * 250) + } + + if len(result.Specs) != len(specs) { + panic("programming error: input / output length don't match") + } + + for i, s := range result.Specs { + specs[i].Source = s.Source + specs[i].Digest = s.Digest + specs[i].LocalName = s.Name + specs[i].TLSVerify = s.TLSVerify + specs[i].ImageID = s.ImageID + } + + return specs, nil } // Schedule new compose by first translating the appropriate blueprint into a pipeline and then