Skip to content

Commit 4c68785

Browse files
authored
Merge pull request #5589 from tonistiigi/ociindex-annotations-fix
Fix invalid index.json annotations on tar=false export
2 parents 147bf0e + 01cf0c6 commit 4c68785

File tree

4 files changed

+454
-12
lines changed

4 files changed

+454
-12
lines changed

client/ociindex/ociindex.go

+73-8
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ package ociindex
33
import (
44
"encoding/json"
55
"io"
6+
"maps"
67
"os"
78
"path"
89
"syscall"
910

11+
"github.com/containerd/containerd/reference"
1012
"github.com/gofrs/flock"
1113
ocispecs "github.com/opencontainers/image-spec/specs-go/v1"
1214
"github.com/pkg/errors"
@@ -15,6 +17,8 @@ import (
1517
const (
1618
// lockFileSuffix is the suffix of the lock file
1719
lockFileSuffix = ".lock"
20+
21+
annotationImageName = "io.containerd.image.name"
1822
)
1923

2024
type StoreIndex struct {
@@ -23,6 +27,19 @@ type StoreIndex struct {
2327
layoutPath string
2428
}
2529

30+
type NameOrTag struct {
31+
isTag bool
32+
value string
33+
}
34+
35+
func Name(name string) NameOrTag {
36+
return NameOrTag{value: name}
37+
}
38+
39+
func Tag(tag string) NameOrTag {
40+
return NameOrTag{isTag: true, value: tag}
41+
}
42+
2643
func NewStoreIndex(storePath string) StoreIndex {
2744
indexPath := path.Join(storePath, ocispecs.ImageIndexFile)
2845
layoutPath := path.Join(storePath, ocispecs.ImageLayoutFile)
@@ -61,7 +78,7 @@ func (s StoreIndex) Read() (*ocispecs.Index, error) {
6178
return &idx, nil
6279
}
6380

64-
func (s StoreIndex) Put(tag string, desc ocispecs.Descriptor) error {
81+
func (s StoreIndex) Put(desc ocispecs.Descriptor, names ...NameOrTag) error {
6582
// lock the store to prevent concurrent access
6683
lock := flock.New(s.lockPath)
6784
locked, err := lock.TryLock()
@@ -107,8 +124,19 @@ func (s StoreIndex) Put(tag string, desc ocispecs.Descriptor) error {
107124
}
108125

109126
setOCIIndexDefaults(&idx)
110-
if err = insertDesc(&idx, desc, tag); err != nil {
111-
return err
127+
128+
namesp := make([]*NameOrTag, 0, len(names))
129+
for _, n := range names {
130+
namesp = append(namesp, &n)
131+
}
132+
if len(names) == 0 {
133+
namesp = append(namesp, nil)
134+
}
135+
136+
for _, name := range namesp {
137+
if err = insertDesc(&idx, desc, name); err != nil {
138+
return err
139+
}
112140
}
113141

114142
idxData, err = json.Marshal(idx)
@@ -130,6 +158,12 @@ func (s StoreIndex) Get(tag string) (*ocispecs.Descriptor, error) {
130158
return nil, err
131159
}
132160

161+
for _, m := range idx.Manifests {
162+
if t, ok := m.Annotations[annotationImageName]; ok && t == tag {
163+
return &m, nil
164+
}
165+
}
166+
133167
for _, m := range idx.Manifests {
134168
if t, ok := m.Annotations[ocispecs.AnnotationRefName]; ok && t == tag {
135169
return &m, nil
@@ -165,20 +199,34 @@ func setOCIIndexDefaults(index *ocispecs.Index) {
165199

166200
// insertDesc puts desc to index with tag.
167201
// Existing manifests with the same tag will be removed from the index.
168-
func insertDesc(index *ocispecs.Index, desc ocispecs.Descriptor, tag string) error {
202+
func insertDesc(index *ocispecs.Index, in ocispecs.Descriptor, name *NameOrTag) error {
169203
if index == nil {
170204
return nil
171205
}
172206

173-
if tag != "" {
207+
// make a copy to not modify the input descriptor
208+
desc := in
209+
desc.Annotations = maps.Clone(in.Annotations)
210+
211+
if name != nil {
174212
if desc.Annotations == nil {
175213
desc.Annotations = make(map[string]string)
176214
}
177-
desc.Annotations[ocispecs.AnnotationRefName] = tag
178-
// remove existing manifests with the same tag
215+
imgName, refName := name.value, name.value
216+
if name.isTag {
217+
imgName = ""
218+
} else {
219+
refName = ociReferenceName(imgName)
220+
}
221+
222+
if imgName != "" {
223+
desc.Annotations[annotationImageName] = imgName
224+
}
225+
desc.Annotations[ocispecs.AnnotationRefName] = refName
226+
// remove existing manifests with the same tag/name
179227
var manifests []ocispecs.Descriptor
180228
for _, m := range index.Manifests {
181-
if m.Annotations[ocispecs.AnnotationRefName] != tag {
229+
if m.Annotations[ocispecs.AnnotationRefName] != refName || m.Annotations[annotationImageName] != imgName {
182230
manifests = append(manifests, m)
183231
}
184232
}
@@ -187,3 +235,20 @@ func insertDesc(index *ocispecs.Index, desc ocispecs.Descriptor, tag string) err
187235
index.Manifests = append(index.Manifests, desc)
188236
return nil
189237
}
238+
239+
// ociReferenceName takes the loosely defined reference name same way as
240+
// containerd tar exporter does.
241+
func ociReferenceName(name string) string {
242+
// OCI defines the reference name as only a tag excluding the
243+
// repository. The containerd annotation contains the full image name
244+
// since the tag is insufficient for correctly naming and referring to an
245+
// image
246+
var ociRef string
247+
if spec, err := reference.Parse(name); err == nil {
248+
ociRef = spec.Object
249+
} else {
250+
ociRef = name
251+
}
252+
253+
return ociRef
254+
}

0 commit comments

Comments
 (0)