Skip to content

Commit a7f37ce

Browse files
authored
Merge pull request #1560 from nalind/pullup-2
"pull up" images when creating them, too
2 parents 945f872 + b0c1c88 commit a7f37ce

File tree

5 files changed

+103
-26
lines changed

5 files changed

+103
-26
lines changed

containers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -666,7 +666,7 @@ func (r *containerStore) create(id string, names []string, image, layer string,
666666
if _, idInUse := r.byid[id]; idInUse {
667667
return nil, ErrDuplicateID
668668
}
669-
names = dedupeNames(names)
669+
names = dedupeStrings(names)
670670
for _, name := range names {
671671
if _, nameInUse := r.byname[name]; nameInUse {
672672
return nil, fmt.Errorf("the container name %q is already in use by %s. You have to remove that container to be able to reuse that name: %w", name, r.byname[name].ID, ErrDuplicateName)

images.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -703,7 +703,7 @@ func (r *imageStore) create(id string, names []string, layer string, options Ima
703703
if _, idInUse := r.byid[id]; idInUse {
704704
return nil, fmt.Errorf("an image with ID %q already exists: %w", id, ErrDuplicateID)
705705
}
706-
names = dedupeNames(names)
706+
names = dedupeStrings(names)
707707
for _, name := range names {
708708
if image, nameInUse := r.byname[name]; nameInUse {
709709
return nil, fmt.Errorf("image name %q is already associated with image %q: %w", name, image.ID, ErrDuplicateName)
@@ -712,7 +712,7 @@ func (r *imageStore) create(id string, names []string, layer string, options Ima
712712
image = &Image{
713713
ID: id,
714714
Digest: options.Digest,
715-
Digests: copyDigestSlice(options.Digests),
715+
Digests: dedupeDigests(options.Digests),
716716
Names: names,
717717
NamesHistory: copyStringSlice(options.NamesHistory),
718718
TopLayer: layer,
@@ -820,7 +820,7 @@ func (r *imageStore) removeName(image *Image, name string) {
820820

821821
// The caller must hold r.inProcessLock for writing.
822822
func (i *Image) addNameToHistory(name string) {
823-
i.NamesHistory = dedupeNames(append([]string{name}, i.NamesHistory...))
823+
i.NamesHistory = dedupeStrings(append([]string{name}, i.NamesHistory...))
824824
}
825825

826826
// Requires startWriting.

layers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1230,7 +1230,7 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
12301230
if duplicateLayer, idInUse := r.byid[id]; idInUse {
12311231
return duplicateLayer, -1, ErrDuplicateID
12321232
}
1233-
names = dedupeNames(names)
1233+
names = dedupeStrings(names)
12341234
for _, name := range names {
12351235
if _, nameInUse := r.byname[name]; nameInUse {
12361236
return nil, -1, ErrDuplicateName

store.go

Lines changed: 97 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,26 +1384,90 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, i
13841384
layer = ilayer.ID
13851385
}
13861386

1387-
var res *Image
1388-
err := s.writeToImageStore(func() error {
1389-
var options ImageOptions
1387+
var options ImageOptions
1388+
var namesToAddAfterCreating []string
1389+
1390+
if err := s.imageStore.startWriting(); err != nil {
1391+
return nil, err
1392+
}
1393+
defer s.imageStore.stopWriting()
1394+
1395+
// Check if the ID refers to an image in a read-only store -- we want
1396+
// to allow images in read-only stores to have their names changed, so
1397+
// if we find one, merge the new values in with what we know about the
1398+
// image that's already there.
1399+
if id != "" {
1400+
for _, is := range s.roImageStores {
1401+
store := is
1402+
if err := store.startReading(); err != nil {
1403+
return nil, err
1404+
}
1405+
defer store.stopReading()
1406+
if i, err := store.Get(id); err == nil {
1407+
// set information about this image in "options"
1408+
options = ImageOptions{
1409+
Metadata: i.Metadata,
1410+
CreationDate: i.Created,
1411+
Digest: i.Digest,
1412+
Digests: copyDigestSlice(i.Digests),
1413+
NamesHistory: copyStringSlice(i.NamesHistory),
1414+
}
1415+
for _, key := range i.BigDataNames {
1416+
data, err := store.BigData(id, key)
1417+
if err != nil {
1418+
return nil, err
1419+
}
1420+
dataDigest, err := store.BigDataDigest(id, key)
1421+
if err != nil {
1422+
return nil, err
1423+
}
1424+
options.BigData = append(options.BigData, ImageBigDataOption{
1425+
Key: key,
1426+
Data: data,
1427+
Digest: dataDigest,
1428+
})
1429+
}
1430+
namesToAddAfterCreating = dedupeStrings(append(append([]string{}, i.Names...), names...))
1431+
break
1432+
}
1433+
}
1434+
}
13901435

1391-
if iOptions != nil {
1392-
options = *iOptions
1393-
options.Digests = copyDigestSlice(iOptions.Digests)
1394-
options.BigData = copyImageBigDataOptionSlice(iOptions.BigData)
1395-
options.NamesHistory = copyStringSlice(iOptions.NamesHistory)
1396-
options.Flags = copyStringInterfaceMap(iOptions.Flags)
1436+
// merge any passed-in options into "options" as best we can
1437+
if iOptions != nil {
1438+
if !iOptions.CreationDate.IsZero() {
1439+
options.CreationDate = iOptions.CreationDate
13971440
}
1398-
if options.CreationDate.IsZero() {
1399-
options.CreationDate = time.Now().UTC()
1441+
if iOptions.Digest != "" {
1442+
options.Digest = iOptions.Digest
14001443
}
1444+
options.Digests = append(options.Digests, copyDigestSlice(iOptions.Digests)...)
1445+
if iOptions.Metadata != "" {
1446+
options.Metadata = iOptions.Metadata
1447+
}
1448+
options.BigData = append(options.BigData, copyImageBigDataOptionSlice(iOptions.BigData)...)
1449+
options.NamesHistory = append(options.NamesHistory, copyStringSlice(iOptions.NamesHistory)...)
1450+
if options.Flags == nil {
1451+
options.Flags = make(map[string]interface{})
1452+
}
1453+
for k, v := range iOptions.Flags {
1454+
options.Flags[k] = v
1455+
}
1456+
}
1457+
1458+
if options.CreationDate.IsZero() {
1459+
options.CreationDate = time.Now().UTC()
1460+
}
1461+
if metadata != "" {
14011462
options.Metadata = metadata
1463+
}
14021464

1403-
var err error
1404-
res, err = s.imageStore.create(id, names, layer, options)
1405-
return err
1406-
})
1465+
res, err := s.imageStore.create(id, names, layer, options)
1466+
if err == nil && len(namesToAddAfterCreating) > 0 {
1467+
// set any names we pulled up from an additional image store, now that we won't be
1468+
// triggering a duplicate names error
1469+
err = s.imageStore.updateNames(res.ID, namesToAddAfterCreating, addNames)
1470+
}
14071471
return res, err
14081472
}
14091473

@@ -2130,18 +2194,30 @@ func (s *store) Exists(id string) bool {
21302194
return s.containerStore.Exists(id)
21312195
}
21322196

2133-
func dedupeNames(names []string) []string {
2134-
seen := make(map[string]bool)
2197+
func dedupeStrings(names []string) []string {
2198+
seen := make(map[string]struct{})
21352199
deduped := make([]string, 0, len(names))
21362200
for _, name := range names {
21372201
if _, wasSeen := seen[name]; !wasSeen {
2138-
seen[name] = true
2202+
seen[name] = struct{}{}
21392203
deduped = append(deduped, name)
21402204
}
21412205
}
21422206
return deduped
21432207
}
21442208

2209+
func dedupeDigests(digests []digest.Digest) []digest.Digest {
2210+
seen := make(map[digest.Digest]struct{})
2211+
deduped := make([]digest.Digest, 0, len(digests))
2212+
for _, d := range digests {
2213+
if _, wasSeen := seen[d]; !wasSeen {
2214+
seen[d] = struct{}{}
2215+
deduped = append(deduped, d)
2216+
}
2217+
}
2218+
return deduped
2219+
}
2220+
21452221
// Deprecated: Prone to race conditions, suggested alternatives are `AddNames` and `RemoveNames`.
21462222
func (s *store) SetNames(id string, names []string) error {
21472223
return s.updateNames(id, names, setNames)
@@ -2156,7 +2232,7 @@ func (s *store) RemoveNames(id string, names []string) error {
21562232
}
21572233

21582234
func (s *store) updateNames(id string, names []string, op updateNameOperation) error {
2159-
deduped := dedupeNames(names)
2235+
deduped := dedupeStrings(names)
21602236

21612237
layerFound := false
21622238
if err := s.writeToLayerStore(func(rlstore rwLayerStore) error {
@@ -2188,11 +2264,12 @@ func (s *store) updateNames(id string, names []string, op updateNameOperation) e
21882264
if i, err := store.Get(id); err == nil {
21892265
// "pull up" the image so that we can change its names list
21902266
options := ImageOptions{
2191-
Metadata: i.Metadata,
21922267
CreationDate: i.Created,
21932268
Digest: i.Digest,
21942269
Digests: copyDigestSlice(i.Digests),
2270+
Metadata: i.Metadata,
21952271
NamesHistory: copyStringSlice(i.NamesHistory),
2272+
Flags: copyStringInterfaceMap(i.Flags),
21962273
}
21972274
for _, key := range i.BigDataNames {
21982275
data, err := store.BigData(id, key)

utils.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,5 +70,5 @@ func applyNameOperation(oldNames []string, opParameters []string, op updateNameO
7070
default:
7171
return result, errInvalidUpdateNameOperation
7272
}
73-
return dedupeNames(result), nil
73+
return dedupeStrings(result), nil
7474
}

0 commit comments

Comments
 (0)