Browse Source

Merge pull request #32293 from moypray/save_delete

Fix delete a image while saving it, delete successfully but failed to save it
Brian Goff 8 years ago
parent
commit
c8141a1fb1
1 changed files with 67 additions and 20 deletions
  1. 67 20
      image/tarexport/save.go

+ 67 - 20
image/tarexport/save.go

@@ -21,8 +21,10 @@ import (
 )
 
 type imageDescriptor struct {
-	refs   []reference.NamedTagged
-	layers []string
+	refs     []reference.NamedTagged
+	layers   []string
+	image    *image.Image
+	layerRef layer.Layer
 }
 
 type saveSession struct {
@@ -39,33 +41,47 @@ func (l *tarexporter) Save(names []string, outStream io.Writer) error {
 		return err
 	}
 
+	// Release all the image top layer references
+	defer l.releaseLayerReferences(images)
 	return (&saveSession{tarexporter: l, images: images}).save(outStream)
 }
 
-func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor, error) {
+// parseNames will parse the image names to a map which contains image.ID to *imageDescriptor.
+// Each imageDescriptor holds an image top layer reference named 'layerRef'. It is taken here, should be released later.
+func (l *tarexporter) parseNames(names []string) (desc map[image.ID]*imageDescriptor, rErr error) {
 	imgDescr := make(map[image.ID]*imageDescriptor)
+	defer func() {
+		if rErr != nil {
+			l.releaseLayerReferences(imgDescr)
+		}
+	}()
 
-	addAssoc := func(id image.ID, ref reference.Named) {
+	addAssoc := func(id image.ID, ref reference.Named) error {
 		if _, ok := imgDescr[id]; !ok {
-			imgDescr[id] = &imageDescriptor{}
+			descr := &imageDescriptor{}
+			if err := l.takeLayerReference(id, descr); err != nil {
+				return err
+			}
+			imgDescr[id] = descr
 		}
 
 		if ref != nil {
 			if _, ok := ref.(reference.Canonical); ok {
-				return
+				return nil
 			}
 			tagged, ok := reference.TagNameOnly(ref).(reference.NamedTagged)
 			if !ok {
-				return
+				return nil
 			}
 
 			for _, t := range imgDescr[id].refs {
 				if tagged.String() == t.String() {
-					return
+					return nil
 				}
 			}
 			imgDescr[id].refs = append(imgDescr[id].refs, tagged)
 		}
+		return nil
 	}
 
 	for _, name := range names {
@@ -78,11 +94,9 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
 			// Check if digest ID reference
 			if digested, ok := ref.(reference.Digested); ok {
 				id := image.IDFromDigest(digested.Digest())
-				_, err := l.is.Get(id)
-				if err != nil {
+				if err := addAssoc(id, nil); err != nil {
 					return nil, err
 				}
-				addAssoc(id, nil)
 				continue
 			}
 			return nil, errors.Errorf("invalid reference: %v", name)
@@ -93,20 +107,26 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
 			if err != nil {
 				return nil, err
 			}
-			addAssoc(imgID, nil)
+			if err := addAssoc(imgID, nil); err != nil {
+				return nil, err
+			}
 			continue
 		}
 		if reference.IsNameOnly(namedRef) {
 			assocs := l.rs.ReferencesByName(namedRef)
 			for _, assoc := range assocs {
-				addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref)
+				if err := addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref); err != nil {
+					return nil, err
+				}
 			}
 			if len(assocs) == 0 {
 				imgID, err := l.is.Search(name)
 				if err != nil {
 					return nil, err
 				}
-				addAssoc(imgID, nil)
+				if err := addAssoc(imgID, nil); err != nil {
+					return nil, err
+				}
 			}
 			continue
 		}
@@ -114,12 +134,43 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
 		if err != nil {
 			return nil, err
 		}
-		addAssoc(image.IDFromDigest(id), namedRef)
+		if err := addAssoc(image.IDFromDigest(id), namedRef); err != nil {
+			return nil, err
+		}
 
 	}
 	return imgDescr, nil
 }
 
+// takeLayerReference will take/Get the image top layer reference
+func (l *tarexporter) takeLayerReference(id image.ID, imgDescr *imageDescriptor) error {
+	img, err := l.is.Get(id)
+	if err != nil {
+		return err
+	}
+	imgDescr.image = img
+	topLayerID := img.RootFS.ChainID()
+	if topLayerID == "" {
+		return nil
+	}
+	layer, err := l.ls.Get(topLayerID)
+	if err != nil {
+		return err
+	}
+	imgDescr.layerRef = layer
+	return nil
+}
+
+// releaseLayerReferences will release all the image top layer references
+func (l *tarexporter) releaseLayerReferences(imgDescr map[image.ID]*imageDescriptor) error {
+	for _, descr := range imgDescr {
+		if descr.layerRef != nil {
+			l.ls.Release(descr.layerRef)
+		}
+	}
+	return nil
+}
+
 func (s *saveSession) save(outStream io.Writer) error {
 	s.savedLayers = make(map[string]struct{})
 	s.diffIDPaths = make(map[layer.DiffID]string)
@@ -224,11 +275,7 @@ func (s *saveSession) save(outStream io.Writer) error {
 }
 
 func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Descriptor, error) {
-	img, err := s.is.Get(id)
-	if err != nil {
-		return nil, err
-	}
-
+	img := s.images[id].image
 	if len(img.RootFS.DiffIDs) == 0 {
 		return nil, fmt.Errorf("empty export - not implemented")
 	}