mirror of
https://github.com/linuxkit/linuxkit.git
synced 2026-03-30 06:31:04 +00:00
Merge pull request #4212 from europaul/fix/nil-deref-release-tag
pkg build: fix nil pointer dereference when releasing image only in registry
This commit is contained in:
@@ -509,7 +509,7 @@ func (p Pkg) Build(bos ...BuildOpt) error {
|
||||
// if requested docker, load the image up
|
||||
// we will store images with arch suffix, i.e. -amd64
|
||||
// if one of the arch equals with system, we will add tag without suffix
|
||||
if bo.targetDocker {
|
||||
if bo.targetDocker && desc != nil {
|
||||
for _, platform := range bo.platforms {
|
||||
ref, err := reference.Parse(p.FullTag())
|
||||
if err != nil {
|
||||
@@ -575,6 +575,21 @@ func (p Pkg) Build(bos ...BuildOpt) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if desc == nil {
|
||||
// Image exists in registry but not in local cache. Pull it so we can create the release tag.
|
||||
_, _ = fmt.Fprintf(writer, "Pulling %s into local cache for release...\n", p.FullTag())
|
||||
if err := c.ImagePull(&ref, bo.platforms, false); err != nil {
|
||||
return fmt.Errorf("unable to pull image for release: %v", err)
|
||||
}
|
||||
desc, err = c.FindDescriptor(&ref)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if desc == nil {
|
||||
return fmt.Errorf("unable to find image descriptor in local cache for %s after pull, cannot release", p.FullTag())
|
||||
}
|
||||
}
|
||||
|
||||
relTag, err := p.ReleaseTag(bo.release)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -240,13 +240,24 @@ type cacheMocker struct {
|
||||
enableIndexWrite bool
|
||||
images map[string][]v1.Descriptor
|
||||
hashes map[string][]byte
|
||||
registryImages map[string][]v1.Descriptor
|
||||
}
|
||||
|
||||
func (c *cacheMocker) ImagePull(ref *reference.Spec, platforms []imagespec.Platform, alwaysPull bool) error {
|
||||
if !c.enableImagePull {
|
||||
return errors.New("ImagePull disabled")
|
||||
}
|
||||
// make some random data for a layer
|
||||
image := ref.String()
|
||||
// simulate pulling from registry: copy registry descriptors into local cache
|
||||
if c.registryImages != nil {
|
||||
if descs, ok := c.registryImages[image]; ok {
|
||||
for _, d := range descs {
|
||||
c.appendImage(image, d)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
// fallback: make some random data for a layer
|
||||
b := make([]byte, 256)
|
||||
_, _ = rand.Read(b)
|
||||
descs, err := c.imageWriteStream(bytes.NewReader(b))
|
||||
@@ -277,6 +288,19 @@ func (c *cacheMocker) ImageInCache(ref *reference.Spec, trustedRef, architecture
|
||||
}
|
||||
|
||||
func (c *cacheMocker) ImageInRegistry(ref *reference.Spec, trustedRef, architecture string) (bool, error) {
|
||||
if c.registryImages == nil {
|
||||
return false, nil
|
||||
}
|
||||
image := ref.String()
|
||||
descs, ok := c.registryImages[image]
|
||||
if !ok {
|
||||
return false, nil
|
||||
}
|
||||
for _, d := range descs {
|
||||
if d.Platform != nil && d.Platform.Architecture == architecture {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
@@ -445,7 +469,7 @@ func (c *cacheMocker) FindDescriptor(ref *reference.Spec) (*v1.Descriptor, error
|
||||
if desc, ok := c.images[name]; ok && len(desc) > 0 {
|
||||
return &desc[0], nil
|
||||
}
|
||||
return nil, fmt.Errorf("not found %s", name)
|
||||
return nil, nil
|
||||
}
|
||||
func (c *cacheMocker) NewSource(ref *reference.Spec, platform *imagespec.Platform, descriptor *v1.Descriptor) spec.ImageSource {
|
||||
return cacheMockerSource{c, ref, platform, descriptor}
|
||||
@@ -581,6 +605,52 @@ func TestBuild(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPushReleaseImageInRegistry tests that push+release works when the image
|
||||
// already exists in the registry but not in the local cache. This is a
|
||||
// regression test for a nil pointer dereference introduced in 4129cc79.
|
||||
func TestPushReleaseImageInRegistry(t *testing.T) {
|
||||
cacheDir := "somecachedir"
|
||||
// simulate an image that exists in the registry for amd64
|
||||
// FullTag() for org:"foo", image:"bar" with no tag set is "docker.io/foo/bar:latest"
|
||||
registryDescs := map[string][]v1.Descriptor{
|
||||
"docker.io/foo/bar:latest": {
|
||||
{
|
||||
MediaType: types.OCIManifestSchema1,
|
||||
Size: 100,
|
||||
Digest: v1.Hash{Algorithm: "sha256", Hex: "aabbccdd"},
|
||||
Platform: &v1.Platform{Architecture: "amd64", OS: "linux"},
|
||||
},
|
||||
},
|
||||
}
|
||||
c := &cacheMocker{
|
||||
enablePush: true,
|
||||
enabledDescriptorWrite: true,
|
||||
enableImagePull: true,
|
||||
enableIndexWrite: true,
|
||||
registryImages: registryDescs,
|
||||
}
|
||||
runner := &dockerMocker{supportContexts: true}
|
||||
p := Pkg{org: "foo", image: "bar", hash: "abc", arches: []string{"amd64"}, commitHash: "HEAD", dockerfile: "testdata/Dockerfile"}
|
||||
opts := []BuildOpt{
|
||||
WithBuildCacheDir(cacheDir),
|
||||
WithBuildPush(),
|
||||
WithRelease("snapshot"),
|
||||
WithBuildDocker(runner),
|
||||
WithBuildCacheProvider(c),
|
||||
WithBuildOutputWriter(io.Discard),
|
||||
WithBuildPlatforms(imagespec.Platform{OS: "linux", Architecture: "amd64"}),
|
||||
}
|
||||
err := p.Build(opts...)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got: %v", err)
|
||||
}
|
||||
// verify the release tag was written to cache
|
||||
relTag := "docker.io/foo/bar:snapshot"
|
||||
if _, ok := c.images[relTag]; !ok {
|
||||
t.Errorf("expected release tag %q to be written to cache", relTag)
|
||||
}
|
||||
}
|
||||
|
||||
// testCheckBuildRun check the output of a build run
|
||||
func testCheckBuildRun(build buildLog, platforms map[string]bool) error {
|
||||
platform := build.platform
|
||||
|
||||
Reference in New Issue
Block a user