diff --git a/pkg/compose/run.go b/pkg/compose/run.go index 51590650cb8..d0284350f59 100644 --- a/pkg/compose/run.go +++ b/pkg/compose/run.go @@ -304,6 +304,9 @@ func (s *composeService) startDependencies(ctx context.Context, project *types.P // passes "never" so an existing dependency is reused as-is Recreate: options.Recreate, RecreateDependencies: options.RecreateDependencies, + // a recreated dependency keeps its anonymous volumes, as with `up`: + // run has no --renew-anon-volumes to opt out + Inherit: true, }) if err != nil { return err diff --git a/pkg/e2e/compose_run_test.go b/pkg/e2e/compose_run_test.go index 3012302e3c0..1bd9e4d3b73 100644 --- a/pkg/e2e/compose_run_test.go +++ b/pkg/e2e/compose_run_test.go @@ -112,6 +112,24 @@ func TestComposeRunNoRecreate(t *testing.T) { ServiceState("dep", "running")) } +func TestComposeRunInheritsAnonymousVolumes(t *testing.T) { + // A dependency whose config-hash diverged is recreated by run like by up, + // but run used to drop its anonymous volumes on the way: the new container + // got a fresh, empty volume, so a database dependency looked wiped. The + // marker is written from the test, not by the container itself, so a fresh + // volume cannot pass the check by writing it again. + NewScenario(t, "run must keep the anonymous volumes of a dependency it recreates, as up does"). + Step("run creates and starts the dependency", + ComposeCmd("run", "task").WithEnv("TAG=one"), + ServiceState("dep", "running")). + Step("data lands in the dependency's anonymous volume", + ComposeCmd("exec", "dep", "sh", "-c", "echo kept > /data/marker")). + Step("a diverged dependency recreated by run still sees that data", + ComposeCmd("run", "task").WithEnv("TAG=two", "COMPOSE_IGNORE_ORPHANS=True"), + Recreated("dep"), + ExecOutputContains("dep", "cat /data/marker", "kept")) +} + func TestComposeRunNotRequiredDeps(t *testing.T) { NewScenario(t, "run must skip a dependency marked required: false when its profile is inactive"). Step("run executes the service without materializing the optional dependency", diff --git a/pkg/e2e/testdata/TestComposeRunInheritsAnonymousVolumes/compose.yaml b/pkg/e2e/testdata/TestComposeRunInheritsAnonymousVolumes/compose.yaml new file mode 100644 index 00000000000..7800caad469 --- /dev/null +++ b/pkg/e2e/testdata/TestComposeRunInheritsAnonymousVolumes/compose.yaml @@ -0,0 +1,18 @@ +services: + task: + image: alpine + command: echo "task done" + depends_on: + - dep + dep: + image: alpine + init: true + command: sleep infinity + volumes: + # anonymous volume: no source, so it lives and dies with the container + # unless carried over on recreate + - /data + environment: + # divergence vector: changing TAG between invocations changes the + # config-hash of dep, which the default policy answers by recreating + TAG: ${TAG:-initial}