feat(agent): report and refuse Compose services built from source; honour --env-file (#7)
This commit is contained in:
@@ -20,6 +20,7 @@ const (
|
||||
labelComposeService = "com.docker.compose.service"
|
||||
labelWorkingDir = "com.docker.compose.project.working_dir"
|
||||
labelConfigFiles = "com.docker.compose.project.config_files"
|
||||
labelEnvFile = "com.docker.compose.project.environment_file"
|
||||
)
|
||||
|
||||
// errorOutputTail is how much of a failed command's output goes into the
|
||||
@@ -80,13 +81,14 @@ type ComposeExecutor struct {
|
||||
resolve *Resolver
|
||||
selfID string
|
||||
run CommandRunner
|
||||
build *BuildChecker
|
||||
}
|
||||
|
||||
// NewComposeExecutor returns an executor for Compose jobs. selfID names the
|
||||
// agent's own container, whose mounts decide which directories may be
|
||||
// touched; run is ExecDocker outside tests.
|
||||
func NewComposeExecutor(cli ComposeDocker, resolve *Resolver, selfID string, run CommandRunner) *ComposeExecutor {
|
||||
return &ComposeExecutor{cli: cli, resolve: resolve, selfID: selfID, run: run}
|
||||
// touched; run and runOut are ExecDocker and ExecDockerOutput outside tests.
|
||||
func NewComposeExecutor(cli ComposeDocker, resolve *Resolver, selfID string, run CommandRunner, runOut OutputRunner) *ComposeExecutor {
|
||||
return &ComposeExecutor{cli: cli, resolve: resolve, selfID: selfID, run: run, build: NewBuildChecker(cli, selfID, runOut)}
|
||||
}
|
||||
|
||||
// Execute pins job.Ref to its current digest, writes it to the stack's
|
||||
@@ -110,6 +112,7 @@ func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, ou
|
||||
}
|
||||
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 {
|
||||
@@ -125,6 +128,20 @@ func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, ou
|
||||
return "", notMounted(workingDir)
|
||||
}
|
||||
|
||||
envs, err := envFiles(roots, envFileLabel)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
// Fresh check, not the inventory's cache: a build: section may have been
|
||||
// added since. Nothing is written for such a service.
|
||||
built, err := e.build.builtServices(ctx, project, workingDir, files[:len(files)-1], envs)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if built[service] {
|
||||
return "", fmt.Errorf("service %s is built from source (build:), not updated", service)
|
||||
}
|
||||
|
||||
pinned, err := e.resolve.Resolve(ctx, job.Ref)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -135,12 +152,7 @@ func (e *ComposeExecutor) Execute(ctx context.Context, job protocol.JobStart, ou
|
||||
return "", err
|
||||
}
|
||||
|
||||
// --project-directory is explicit because, with -f, compose would take it
|
||||
// from the first file, which differs for stacks started with the flag.
|
||||
base := []string{"compose", "-p", project, "--project-directory", workingDir}
|
||||
for _, f := range files {
|
||||
base = append(base, "-f", f)
|
||||
}
|
||||
base := composeBase(project, workingDir, files, envs)
|
||||
for _, step := range [][]string{{"pull", service}, {"up", "-d", service}} {
|
||||
args := append(append([]string(nil), base...), step...)
|
||||
fmt.Fprintf(out, "$ docker %s\n", strings.Join(args, " "))
|
||||
|
||||
Reference in New Issue
Block a user