fix(provider): guard down's stopContainer against the relay too

glours' review flagged the same bug class this PR already fixes for
start/restart: stopContainer (down.go) runs PreStop hooks
unconditionally, and runHook execs into the container -- which fails
against a shell-less relay. Guarded it the same way, with a regression
test.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Signed-off-by: Nicolas De Loof <[email protected]>
This commit is contained in:
Nicolas De Loof
2026-09-17 17:51:23 +02:00
committed by Guillaume Lours
co-authored by Claude Sonnet 5
parent b06424e0b9
commit bb22a260e8
2 changed files with 22 additions and 1 deletions
+1 -1
View File
@@ -311,7 +311,7 @@ func (s *composeService) stopContainer(ctx context.Context, service *types.Servi
eventName := getContainerProgressName(ctr)
s.events.On(newEvent(eventName, api.Working, api.StatusStopping))
if service != nil {
if service != nil && !isRelayContainer(ctr) {
for _, hook := range service.PreStop {
err := s.runHook(ctx, ctr, *service, hook, listener)
if err != nil {
+21
View File
@@ -676,6 +676,27 @@ func TestDownHookContainerRemovalFailureIsNonFatal(t *testing.T) {
assert.NilError(t, err)
}
// A relay stands in for the service on the network but is a shell-less
// scratch binary: pre_stop has no process inside it to act on. No
// ExecCreate expectation is set: per newStartTestService, gomock fails the
// test if the hook still runs.
func TestStopContainerSkipsPreStopForRelay(t *testing.T) {
svc, apiClient, _ := newStartTestService(t)
service := types.ServiceConfig{
Name: "db",
PreStop: []types.ServiceHook{{Command: types.ShellCommand{"quiesce"}}},
}
relay := serviceContainer("db", 1, container.StateRunning)
relay.Labels[compose.RelayLabel] = "abc123"
apiClient.EXPECT().ContainerStop(gomock.Any(), relay.ID, gomock.Any()).
Return(client.ContainerStopResult{}, nil)
err := svc.stopContainer(t.Context(), &service, relay, nil, nil)
assert.NilError(t, err)
}
// runningOneOff builds a RUNNING `compose run` container of the given service.
func runningOneOff(service, id string) container.Summary {
c := testContainer(service, id, true)