mirror of
https://github.com/docker/compose.git
synced 2026-09-27 01:42:08 +00:00
pre_start hooks run as ephemeral init containers with their own image (ServiceHook.Image), but that image was ignored by image resolution: `config --images` didn't list it, `pull` didn't fetch it, and `up` failed at runtime with "No such image" when it wasn't already present locally. Add a GetDependentImages helper that returns a service's pre_start hook images, and use it wherever service images are collected/pulled: getLocalImagesDigests, pullRequiredImages (up path), the pull command, and `config --images`. Hook images inherit the parent service pull policy. post_start/pre_stop hooks run via ExecCreate inside the service container and never use hook.Image, so they are intentionally out of scope. Digest resolution/locking (--resolve-image-digests / --lock-image-digests) is not covered: compose-go's WithImagesResolved only resolves service.Image (needs an upstream change), and the --lock-image-digests override merges pre_start by concatenation, which would duplicate hooks. Signed-off-by: Nicolas De Loof <nicolas.deloof@gmail.com>
87 lines
2.3 KiB
Go
87 lines
2.3 KiB
Go
/*
|
|
Copyright 2020 Docker Compose CLI authors
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package api
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/compose-spec/compose-go/v2/types"
|
|
"gotest.tools/v3/assert"
|
|
)
|
|
|
|
func TestRunOptionsEnvironmentMap(t *testing.T) {
|
|
opts := RunOptions{
|
|
Environment: []string{
|
|
"FOO=BAR",
|
|
"ZOT=",
|
|
"QIX",
|
|
},
|
|
}
|
|
env := types.NewMappingWithEquals(opts.Environment)
|
|
assert.Equal(t, *env["FOO"], "BAR")
|
|
assert.Equal(t, *env["ZOT"], "")
|
|
assert.Check(t, env["QIX"] == nil)
|
|
}
|
|
|
|
func TestGetDependentImages(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
service types.ServiceConfig
|
|
expected []string
|
|
}{
|
|
{
|
|
name: "no hooks",
|
|
service: types.ServiceConfig{Image: "alpine:3.20"},
|
|
expected: nil,
|
|
},
|
|
{
|
|
name: "pre_start hook with explicit image",
|
|
service: types.ServiceConfig{
|
|
Image: "alpine:3.20",
|
|
PreStart: []types.ServiceHook{
|
|
{Image: "alpine:3.19", Command: types.ShellCommand{"echo", "init"}},
|
|
},
|
|
},
|
|
expected: []string{"alpine:3.19"},
|
|
},
|
|
{
|
|
name: "pre_start hook without image is ignored",
|
|
service: types.ServiceConfig{
|
|
Image: "alpine:3.20",
|
|
PreStart: []types.ServiceHook{
|
|
{Image: "busybox", Command: types.ShellCommand{"echo", "a"}},
|
|
{Command: types.ShellCommand{"echo", "b"}},
|
|
},
|
|
},
|
|
expected: []string{"busybox"},
|
|
},
|
|
{
|
|
name: "post_start and pre_stop hooks are not collected",
|
|
service: types.ServiceConfig{
|
|
Image: "alpine:3.20",
|
|
PostStart: []types.ServiceHook{{Image: "ignored:post", Command: types.ShellCommand{"echo"}}},
|
|
PreStop: []types.ServiceHook{{Image: "ignored:stop", Command: types.ShellCommand{"echo"}}},
|
|
},
|
|
expected: nil,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.DeepEqual(t, GetDependentImages(tt.service), tt.expected)
|
|
})
|
|
}
|
|
}
|