This commit was merged in pull request #32.
This commit is contained in:
@@ -6,13 +6,12 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/filters"
|
||||
|
||||
"github.com/shcizo/package-updater/internal/protocol"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -71,6 +70,7 @@ func dockerEnv() []string {
|
||||
// ComposeDocker is the subset of the Docker SDK ComposeExecutor needs.
|
||||
type ComposeDocker interface {
|
||||
SelfInspector
|
||||
HelperDocker
|
||||
ContainerList(ctx context.Context, opts container.ListOptions) ([]container.Summary, error)
|
||||
}
|
||||
|
||||
@@ -95,7 +95,10 @@ func NewComposeExecutor(cli ComposeDocker, resolve *Resolver, selfID string, run
|
||||
// is), writes it to the stack's override file and recreates the service.
|
||||
// Working directory and config files come from the service's container
|
||||
// labels on this machine, never from the job. It returns the pinned ref.
|
||||
func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, out io.Writer) (string, error) {
|
||||
//
|
||||
// When the service is the agent's own container, the recreate runs in a
|
||||
// helper container instead (see selfUpdate), because it stops this process.
|
||||
func (e *ComposeExecutor) Execute(ctx context.Context, job Job, out io.Writer) (string, error) {
|
||||
project, service := job.ComposeProject, job.ComposeService
|
||||
cts, err := e.cli.ContainerList(ctx, container.ListOptions{
|
||||
All: true,
|
||||
@@ -110,14 +113,24 @@ func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, ou
|
||||
if len(cts) == 0 {
|
||||
return "", fmt.Errorf("no container for compose service %s/%s on this machine", project, service)
|
||||
}
|
||||
self, err := inspectSelf(ctx, e.cli, e.selfID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
isSelf := self.ContainerJSONBase != nil && self.ID != "" &&
|
||||
slices.ContainsFunc(cts, func(ct container.Summary) bool { return ct.ID == self.ID })
|
||||
// What an update of the agent's own service has printed so far goes into
|
||||
// the helper's labels.
|
||||
var soFar *tailBuffer
|
||||
if isSelf {
|
||||
soFar = &tailBuffer{max: selfUpdateOutputMax}
|
||||
out = io.MultiWriter(out, tailWriter{soFar})
|
||||
}
|
||||
workingDir := cts[0].Labels[labelWorkingDir]
|
||||
configFiles := cts[0].Labels[labelConfigFiles]
|
||||
envFileLabel := cts[0].Labels[labelEnvFile]
|
||||
|
||||
roots, err := MountRoots(ctx, e.cli, e.selfID)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
roots := rootsOf(self)
|
||||
files, dir, err := composeFiles(roots, configFiles)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -163,13 +176,29 @@ func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, ou
|
||||
}
|
||||
|
||||
base := composeBase(project, workingDir, files, envs)
|
||||
for _, step := range [][]string{{"pull", service}, {"up", "-d", service}} {
|
||||
args := append(append([]string(nil), base...), step...)
|
||||
run := func(args []string) error {
|
||||
fmt.Fprintf(out, "$ docker %s\n", strings.Join(args, " "))
|
||||
tail := &tailBuffer{max: errorOutputTail}
|
||||
if err := e.run(ctx, workingDir, io.MultiWriter(out, tailWriter{tail}), args...); err != nil {
|
||||
return "", fmt.Errorf("docker compose %s: %w (output: %s)", step[0], err, strings.TrimSpace(tail.String()))
|
||||
return composeError(args[len(base)], err, tail)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
if err := run(append(append([]string(nil), base...), "pull", service)); err != nil {
|
||||
return "", err
|
||||
}
|
||||
up := append(append([]string(nil), base...), "up", "-d", service)
|
||||
if isSelf {
|
||||
return e.selfUpdate(ctx, job, self, workingDir, up, pinned, out, soFar)
|
||||
}
|
||||
if err := run(up); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return pinned, nil
|
||||
}
|
||||
|
||||
// composeError describes a failed `docker compose <step>` call with the tail
|
||||
// of its output.
|
||||
func composeError(step string, err error, tail *tailBuffer) error {
|
||||
return fmt.Errorf("docker compose %s: %w (output: %s)", step, err, strings.TrimSpace(tail.String()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user