diff --git a/spindle/engines/nixery/engine.go b/spindle/engines/nixery/engine.go index f5dc39d1..a06d34bf 100644 --- a/spindle/engines/nixery/engine.go +++ b/spindle/engines/nixery/engine.go @@ -35,9 +35,10 @@ const ( type cleanupFunc func(context.Context) error type Engine struct { - docker client.APIClient - l *slog.Logger - cfg *config.Config + dockerMu sync.Mutex + docker client.APIClient + l *slog.Logger + cfg *config.Config slotter engine.WorkflowSlotter @@ -164,15 +165,9 @@ func workflowImage(deps map[string][]string, nixery string) string { } func New(ctx context.Context, cfg *config.Config) (*Engine, error) { - dcli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - if err != nil { - return nil, err - } - l := log.FromContext(ctx).With("component", "spindle") e := &Engine{ - docker: dcli, l: l, cfg: cfg, slotter: engine.NewSemaphoreSlotter(cfg.NixeryPipelines.MaxConcurrentWorkflows), @@ -183,6 +178,22 @@ func New(ctx context.Context, cfg *config.Config) (*Engine, error) { return e, nil } +func (e *Engine) ensureDocker() (client.APIClient, error) { + e.dockerMu.Lock() + defer e.dockerMu.Unlock() + + if e.docker != nil { + return e.docker, nil + } + + dcli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + if err != nil { + return nil, err + } + e.docker = dcli + return dcli, nil +} + func (e *Engine) AcquireWorkflowSlot( ctx context.Context, wid models.WorkflowId, @@ -215,6 +226,10 @@ func (e *Engine) SetupWorkflow(ctx context.Context, wid models.WorkflowId, wf *m } }() + if _, err := e.ensureDocker(); err != nil { + return err + } + /// -------------------------NETWORK CREATION--------------------------------------- _, err = e.docker.NetworkCreate(ctx, networkName(wid), network.CreateOptions{ Driver: "bridge", diff --git a/spindle/engines/nixery/engine_test.go b/spindle/engines/nixery/engine_test.go new file mode 100644 index 00000000..1cca8754 --- /dev/null +++ b/spindle/engines/nixery/engine_test.go @@ -0,0 +1,25 @@ +package nixery + +import ( + "context" + "testing" + + "tangled.org/core/spindle/config" +) + +func TestNewDefersDockerClientUntilWorkflowSetup(t *testing.T) { + t.Setenv("DOCKER_HOST", "tcp://127.0.0.1:2376") + t.Setenv("DOCKER_TLS_VERIFY", "1") + t.Setenv("DOCKER_CERT_PATH", t.TempDir()) + + e, err := New(context.Background(), &config.Config{}) + if err != nil { + t.Fatal(err) + } + if e.docker != nil { + t.Fatal("docker client initialized during engine initialization") + } + if _, err := e.ensureDocker(); err == nil { + t.Fatal("expected incomplete Docker TLS configuration to fail when first used") + } +}