Skip to content

An image represents a manifest (and is a blob) and also references a config #20458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion pkg/image/registry/imagestream/etcd/etcd.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func (r *LayersREST) Get(ctx context.Context, name string, options *metav1.GetOp
isl.Blobs[layer.Name] = imageapi.ImageLayerData{LayerSize: &layer.LayerSize, MediaType: layer.MediaType}
}
}
if blob := entry.Manifest; blob != nil {
if blob := entry.Config; blob != nil {
reference.Manifest = &blob.Name
if _, ok := isl.Blobs[blob.Name]; !ok {
if blob.LayerSize == 0 {
Expand All @@ -203,6 +203,10 @@ func (r *LayersREST) Get(ctx context.Context, name string, options *metav1.GetOp
}
}
}
// the image manifest is always a blob - schema2 images also have a config blob referenced from the manifest
if _, ok := isl.Blobs[item.Image]; !ok {
isl.Blobs[item.Image] = imageapi.ImageLayerData{MediaType: entry.MediaType}
}
isl.Images[item.Image] = reference
}
}
Expand Down
30 changes: 19 additions & 11 deletions pkg/image/registry/imagestream/etcd/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,10 @@ func NewImageLayerIndex(lw ImageListWatch) ImageLayerIndex {
return imageLayerIndex{informer: informer}
}

// manifestFromImage attempts to find a manifest blob description from
// an image. Images older than schema2 in Docker do not have a manifest blob.
func manifestFromImage(image *imagev1.Image) *imagev1.ImageLayer {
// configFromImage attempts to find a config blob description from
// an image. Images older than schema2 in Docker do not have a config blob - the manifest
// has that data embedded.
func configFromImage(image *imagev1.Image) *imagev1.ImageLayer {
if image.DockerImageManifestMediaType != "application/vnd.docker.distribution.manifest.v2+json" {
return nil
}
Expand All @@ -134,7 +135,7 @@ func manifestFromImage(image *imagev1.Image) *imagev1.ImageLayer {
}
return &imagev1.ImageLayer{
Name: meta.ID,
MediaType: image.DockerImageManifestMediaType,
MediaType: "application/vnd.docker.container.image.v1+json",
}
}

Expand All @@ -145,16 +146,22 @@ func manifestFromImage(image *imagev1.Image) *imagev1.ImageLayer {
type ImageLayers struct {
Name string
ResourceVersion string
Manifest *imagev1.ImageLayer
MediaType string
Config *imagev1.ImageLayer
Layers []imagev1.ImageLayer
}

func imageLayersForImage(image *imagev1.Image) *ImageLayers {
mediaType := image.DockerImageManifestMediaType
if len(mediaType) == 0 {
mediaType = "application/vnd.docker.distribution.manifest.v2+json"
}
return &ImageLayers{
Name: image.Name,
ResourceVersion: image.ResourceVersion,
MediaType: mediaType,
Config: configFromImage(image),
Layers: image.DockerImageLayers,
Manifest: manifestFromImage(image),
}
}

Expand All @@ -170,15 +177,16 @@ func (l *ImageLayers) DeepCopyObject() runtime.Object {
layers = make([]imagev1.ImageLayer, len(l.Layers))
copy(layers, l.Layers)
}
var manifest *imagev1.ImageLayer
if l.Manifest != nil {
copied := *l.Manifest
manifest = &copied
var config *imagev1.ImageLayer
if l.Config != nil {
copied := *l.Config
config = &copied
}
return &ImageLayers{
Name: l.Name,
ResourceVersion: l.ResourceVersion,
Manifest: manifest,
MediaType: l.MediaType,
Config: config,
Layers: layers,
}
}
Expand Down
4 changes: 4 additions & 0 deletions test/extended/images/layers.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,14 @@ var _ = g.Describe("[Feature:ImageLayers] Image layer subresource", func() {
o.Expect(ok).To(o.BeTrue())
o.Expect(len(l.Layers)).To(o.BeNumerically(">", 0))
o.Expect(l.Manifest).ToNot(o.BeNil())
o.Expect(layers.Blobs[*l.Manifest]).ToNot(o.BeNil())
o.Expect(layers.Blobs[*l.Manifest].MediaType).To(o.Equal("application/vnd.docker.container.image.v1+json"))
for _, layerID := range l.Layers {
o.Expect(layers.Blobs).To(o.HaveKey(layerID))
o.Expect(layers.Blobs[layerID].MediaType).NotTo(o.BeEmpty())
}
o.Expect(layers.Blobs).To(o.HaveKey(image.Image.Name))
o.Expect(layers.Blobs[image.Image.Name].MediaType).To(o.Equal("application/vnd.docker.distribution.manifest.v2+json"))
if i == 0 {
busyboxLayers = l.Layers
}
Expand Down