diff --git a/daemon/containerd/cache.go b/daemon/containerd/cache.go index 1fbf32c669..9f957a7696 100644 --- a/daemon/containerd/cache.go +++ b/daemon/containerd/cache.go @@ -11,6 +11,7 @@ import ( "github.com/docker/docker/builder" "github.com/docker/docker/errdefs" "github.com/docker/docker/image" + "github.com/docker/docker/image/cache" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -98,7 +99,7 @@ func (ic *localCache) GetCache(parentID string, cfg *container.Config) (imageID return "", err } - if isMatch(&cc, cfg) { + if cache.CompareConfig(&cc, cfg) { childImage, err := ic.imageService.GetImage(ctx, child.String(), backend.GetImageOpts{}) if err != nil { return "", err @@ -206,61 +207,3 @@ func (ic *imageCache) isParent(ctx context.Context, img *image.Image, parentID i } return ic.isParent(ctx, p, parentID) } - -// compare two Config struct. Do not compare the "Image" nor "Hostname" fields -// If OpenStdin is set, then it differs -func isMatch(a, b *container.Config) bool { - if a == nil || b == nil || - a.OpenStdin || b.OpenStdin { - return false - } - if a.AttachStdout != b.AttachStdout || - a.AttachStderr != b.AttachStderr || - a.User != b.User || - a.OpenStdin != b.OpenStdin || - a.Tty != b.Tty { - return false - } - - if len(a.Cmd) != len(b.Cmd) || - len(a.Env) != len(b.Env) || - len(a.Labels) != len(b.Labels) || - len(a.ExposedPorts) != len(b.ExposedPorts) || - len(a.Entrypoint) != len(b.Entrypoint) || - len(a.Volumes) != len(b.Volumes) { - return false - } - - for i := 0; i < len(a.Cmd); i++ { - if a.Cmd[i] != b.Cmd[i] { - return false - } - } - for i := 0; i < len(a.Env); i++ { - if a.Env[i] != b.Env[i] { - return false - } - } - for k, v := range a.Labels { - if v != b.Labels[k] { - return false - } - } - for k := range a.ExposedPorts { - if _, exists := b.ExposedPorts[k]; !exists { - return false - } - } - - for i := 0; i < len(a.Entrypoint); i++ { - if a.Entrypoint[i] != b.Entrypoint[i] { - return false - } - } - for key := range a.Volumes { - if _, exists := b.Volumes[key]; !exists { - return false - } - } - return true -} diff --git a/image/cache/compare.go b/image/cache/compare.go index e31e9c8bdf..ec1971a207 100644 --- a/image/cache/compare.go +++ b/image/cache/compare.go @@ -4,42 +4,69 @@ import ( "github.com/docker/docker/api/types/container" ) -// compare two Config struct. Do not compare the "Image" nor "Hostname" fields -// If OpenStdin is set, then it differs +// TODO: Remove once containerd image service directly uses the ImageCache and +// LocalImageCache structs. +func CompareConfig(a, b *container.Config) bool { + return compare(a, b) +} + +// compare two Config struct. Do not container-specific fields: +// - Image +// - Hostname +// - Domainname +// - MacAddress func compare(a, b *container.Config) bool { - if a == nil || b == nil || - a.OpenStdin || b.OpenStdin { - return false - } - if a.AttachStdout != b.AttachStdout || - a.AttachStderr != b.AttachStderr || - a.User != b.User || - a.OpenStdin != b.OpenStdin || - a.Tty != b.Tty { + if a == nil || b == nil { return false } - if len(a.Cmd) != len(b.Cmd) || - len(a.Env) != len(b.Env) || - len(a.Labels) != len(b.Labels) || - len(a.ExposedPorts) != len(b.ExposedPorts) || - len(a.Entrypoint) != len(b.Entrypoint) || - len(a.Volumes) != len(b.Volumes) { + if len(a.Env) != len(b.Env) { + return false + } + if len(a.Cmd) != len(b.Cmd) { + return false + } + if len(a.Entrypoint) != len(b.Entrypoint) { + return false + } + if len(a.Shell) != len(b.Shell) { + return false + } + if len(a.ExposedPorts) != len(b.ExposedPorts) { + return false + } + if len(a.Volumes) != len(b.Volumes) { + return false + } + if len(a.Labels) != len(b.Labels) { + return false + } + if len(a.OnBuild) != len(b.OnBuild) { return false } - for i := 0; i < len(a.Cmd); i++ { - if a.Cmd[i] != b.Cmd[i] { - return false - } - } for i := 0; i < len(a.Env); i++ { if a.Env[i] != b.Env[i] { return false } } - for k, v := range a.Labels { - if v != b.Labels[k] { + for i := 0; i < len(a.OnBuild); i++ { + if a.OnBuild[i] != b.OnBuild[i] { + return false + } + } + for i := 0; i < len(a.Cmd); i++ { + if a.Cmd[i] != b.Cmd[i] { + return false + } + } + for i := 0; i < len(a.Entrypoint); i++ { + if a.Entrypoint[i] != b.Entrypoint[i] { + return false + } + } + for i := 0; i < len(a.Shell); i++ { + if a.Shell[i] != b.Shell[i] { return false } } @@ -48,16 +75,87 @@ func compare(a, b *container.Config) bool { return false } } - - for i := 0; i < len(a.Entrypoint); i++ { - if a.Entrypoint[i] != b.Entrypoint[i] { - return false - } - } for key := range a.Volumes { if _, exists := b.Volumes[key]; !exists { return false } } + for k, v := range a.Labels { + if v != b.Labels[k] { + return false + } + } + + if a.AttachStdin != b.AttachStdin { + return false + } + if a.AttachStdout != b.AttachStdout { + return false + } + if a.AttachStderr != b.AttachStderr { + return false + } + if a.NetworkDisabled != b.NetworkDisabled { + return false + } + if a.Tty != b.Tty { + return false + } + if a.OpenStdin != b.OpenStdin { + return false + } + if a.StdinOnce != b.StdinOnce { + return false + } + if a.ArgsEscaped != b.ArgsEscaped { + return false + } + if a.User != b.User { + return false + } + if a.WorkingDir != b.WorkingDir { + return false + } + if a.StopSignal != b.StopSignal { + return false + } + + if (a.StopTimeout == nil) != (b.StopTimeout == nil) { + return false + } + if a.StopTimeout != nil && b.StopTimeout != nil { + if *a.StopTimeout != *b.StopTimeout { + return false + } + } + if (a.Healthcheck == nil) != (b.Healthcheck == nil) { + return false + } + if a.Healthcheck != nil && b.Healthcheck != nil { + if a.Healthcheck.Interval != b.Healthcheck.Interval { + return false + } + if a.Healthcheck.StartInterval != b.Healthcheck.StartInterval { + return false + } + if a.Healthcheck.StartPeriod != b.Healthcheck.StartPeriod { + return false + } + if a.Healthcheck.Timeout != b.Healthcheck.Timeout { + return false + } + if a.Healthcheck.Retries != b.Healthcheck.Retries { + return false + } + if len(a.Healthcheck.Test) != len(b.Healthcheck.Test) { + return false + } + for i := 0; i < len(a.Healthcheck.Test); i++ { + if a.Healthcheck.Test[i] != b.Healthcheck.Test[i] { + return false + } + } + } + return true }