also fix a typo in pkg/truncindex package comment
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
| ... | ... |
@@ -193,7 +193,7 @@ func (d Docker) Copy(c *daemon.Container, destPath string, src builder.FileInfo, |
| 193 | 193 |
// GetCachedImage returns a reference to a cached image whose parent equals `parent` |
| 194 | 194 |
// and runconfig equals `cfg`. A cache miss is expected to return an empty ID and a nil error. |
| 195 | 195 |
func (d Docker) GetCachedImage(imgID string, cfg *runconfig.Config) (string, error) {
|
| 196 |
- cache, err := d.Daemon.ImageGetCached(string(imgID), cfg) |
|
| 196 |
+ cache, err := d.Daemon.ImageGetCached(imgID, cfg) |
|
| 197 | 197 |
if cache == nil || err != nil {
|
| 198 | 198 |
return "", err |
| 199 | 199 |
} |
| ... | ... |
@@ -279,7 +279,7 @@ func (daemon *Daemon) checkImageDeleteHardConflict(img *image.Image) *imageDelet |
| 279 | 279 |
} |
| 280 | 280 |
|
| 281 | 281 |
// Check if the image has any descendent images. |
| 282 |
- if daemon.Graph().HasChildren(img) {
|
|
| 282 |
+ if daemon.Graph().HasChildren(img.ID) {
|
|
| 283 | 283 |
return &imageDeleteConflict{
|
| 284 | 284 |
hard: true, |
| 285 | 285 |
imgID: img.ID, |
| ... | ... |
@@ -337,5 +337,5 @@ func (daemon *Daemon) checkImageDeleteSoftConflict(img *image.Image) *imageDelet |
| 337 | 337 |
// that there are no repository references to the given image and it has no |
| 338 | 338 |
// child images. |
| 339 | 339 |
func (daemon *Daemon) imageIsDangling(img *image.Image) bool {
|
| 340 |
- return !(daemon.repositories.HasReferences(img) || daemon.Graph().HasChildren(img)) |
|
| 340 |
+ return !(daemon.Repositories().HasReferences(img) || daemon.Graph().HasChildren(img.ID)) |
|
| 341 | 341 |
} |
| ... | ... |
@@ -104,6 +104,7 @@ type Graph struct {
|
| 104 | 104 |
tarSplitDisabled bool |
| 105 | 105 |
uidMaps []idtools.IDMap |
| 106 | 106 |
gidMaps []idtools.IDMap |
| 107 |
+ parentRefs map[string]int |
|
| 107 | 108 |
} |
| 108 | 109 |
|
| 109 | 110 |
// file names for ./graph/<ID>/ |
| ... | ... |
@@ -141,12 +142,13 @@ func NewGraph(root string, driver graphdriver.Driver, uidMaps, gidMaps []idtools |
| 141 | 141 |
} |
| 142 | 142 |
|
| 143 | 143 |
graph := &Graph{
|
| 144 |
- root: abspath, |
|
| 145 |
- idIndex: truncindex.NewTruncIndex([]string{}),
|
|
| 146 |
- driver: driver, |
|
| 147 |
- retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
|
|
| 148 |
- uidMaps: uidMaps, |
|
| 149 |
- gidMaps: gidMaps, |
|
| 144 |
+ root: abspath, |
|
| 145 |
+ idIndex: truncindex.NewTruncIndex([]string{}),
|
|
| 146 |
+ driver: driver, |
|
| 147 |
+ retained: &retainedLayers{layerHolders: make(map[string]map[string]struct{})},
|
|
| 148 |
+ uidMaps: uidMaps, |
|
| 149 |
+ gidMaps: gidMaps, |
|
| 150 |
+ parentRefs: make(map[string]int), |
|
| 150 | 151 |
} |
| 151 | 152 |
|
| 152 | 153 |
// Windows does not currently support tarsplit functionality. |
| ... | ... |
@@ -174,6 +176,20 @@ func (graph *Graph) restore() error {
|
| 174 | 174 |
for _, v := range dir {
|
| 175 | 175 |
id := v.Name() |
| 176 | 176 |
if graph.driver.Exists(id) {
|
| 177 |
+ pth := filepath.Join(graph.root, id, "json") |
|
| 178 |
+ jsonSource, err := os.Open(pth) |
|
| 179 |
+ if err != nil {
|
|
| 180 |
+ return err |
|
| 181 |
+ } |
|
| 182 |
+ defer jsonSource.Close() |
|
| 183 |
+ decoder := json.NewDecoder(jsonSource) |
|
| 184 |
+ var img *image.Image |
|
| 185 |
+ if err := decoder.Decode(img); err != nil {
|
|
| 186 |
+ return err |
|
| 187 |
+ } |
|
| 188 |
+ graph.imageMutex.Lock(img.Parent) |
|
| 189 |
+ graph.parentRefs[img.Parent]++ |
|
| 190 |
+ graph.imageMutex.Unlock(img.Parent) |
|
| 177 | 191 |
ids = append(ids, id) |
| 178 | 192 |
} |
| 179 | 193 |
} |
| ... | ... |
@@ -326,7 +342,13 @@ func (graph *Graph) register(im image.Descriptor, layerData io.Reader) (err erro |
| 326 | 326 |
if err := os.Rename(tmp, graph.imageRoot(imgID)); err != nil {
|
| 327 | 327 |
return err |
| 328 | 328 |
} |
| 329 |
- graph.idIndex.Add(imgID) |
|
| 329 |
+ |
|
| 330 |
+ graph.idIndex.Add(img.ID) |
|
| 331 |
+ |
|
| 332 |
+ graph.imageMutex.Lock(img.Parent) |
|
| 333 |
+ graph.parentRefs[img.Parent]++ |
|
| 334 |
+ graph.imageMutex.Unlock(img.Parent) |
|
| 335 |
+ |
|
| 330 | 336 |
return nil |
| 331 | 337 |
} |
| 332 | 338 |
|
| ... | ... |
@@ -393,6 +415,10 @@ func (graph *Graph) Delete(name string) error {
|
| 393 | 393 |
if err != nil {
|
| 394 | 394 |
return err |
| 395 | 395 |
} |
| 396 |
+ img, err := graph.Get(id) |
|
| 397 |
+ if err != nil {
|
|
| 398 |
+ return err |
|
| 399 |
+ } |
|
| 396 | 400 |
tmp, err := graph.mktemp() |
| 397 | 401 |
graph.idIndex.Delete(id) |
| 398 | 402 |
if err == nil {
|
| ... | ... |
@@ -407,6 +433,14 @@ func (graph *Graph) Delete(name string) error {
|
| 407 | 407 |
} |
| 408 | 408 |
// Remove rootfs data from the driver |
| 409 | 409 |
graph.driver.Remove(id) |
| 410 |
+ |
|
| 411 |
+ graph.imageMutex.Lock(img.Parent) |
|
| 412 |
+ graph.parentRefs[img.Parent]-- |
|
| 413 |
+ if graph.parentRefs[img.Parent] == 0 {
|
|
| 414 |
+ delete(graph.parentRefs, img.Parent) |
|
| 415 |
+ } |
|
| 416 |
+ graph.imageMutex.Unlock(img.Parent) |
|
| 417 |
+ |
|
| 410 | 418 |
// Remove the trashed image directory |
| 411 | 419 |
return os.RemoveAll(tmp) |
| 412 | 420 |
} |
| ... | ... |
@@ -424,9 +458,11 @@ func (graph *Graph) Map() map[string]*image.Image {
|
| 424 | 424 |
// The walking order is undetermined. |
| 425 | 425 |
func (graph *Graph) walkAll(handler func(*image.Image)) {
|
| 426 | 426 |
graph.idIndex.Iterate(func(id string) {
|
| 427 |
- if img, err := graph.Get(id); err != nil {
|
|
| 427 |
+ img, err := graph.Get(id) |
|
| 428 |
+ if err != nil {
|
|
| 428 | 429 |
return |
| 429 |
- } else if handler != nil {
|
|
| 430 |
+ } |
|
| 431 |
+ if handler != nil {
|
|
| 430 | 432 |
handler(img) |
| 431 | 433 |
} |
| 432 | 434 |
}) |
| ... | ... |
@@ -453,8 +489,11 @@ func (graph *Graph) ByParent() map[string][]*image.Image {
|
| 453 | 453 |
} |
| 454 | 454 |
|
| 455 | 455 |
// HasChildren returns whether the given image has any child images. |
| 456 |
-func (graph *Graph) HasChildren(img *image.Image) bool {
|
|
| 457 |
- return len(graph.ByParent()[img.ID]) > 0 |
|
| 456 |
+func (graph *Graph) HasChildren(imgID string) bool {
|
|
| 457 |
+ graph.imageMutex.Lock(imgID) |
|
| 458 |
+ count := graph.parentRefs[imgID] |
|
| 459 |
+ graph.imageMutex.Unlock(imgID) |
|
| 460 |
+ return count > 0 |
|
| 458 | 461 |
} |
| 459 | 462 |
|
| 460 | 463 |
// Retain keeps the images and layers that are in the pulling chain so that |
| ... | ... |
@@ -472,11 +511,10 @@ func (graph *Graph) Release(sessionID string, layerIDs ...string) {
|
| 472 | 472 |
// A head is an image which is not the parent of another image in the graph. |
| 473 | 473 |
func (graph *Graph) Heads() map[string]*image.Image {
|
| 474 | 474 |
heads := make(map[string]*image.Image) |
| 475 |
- byParent := graph.ByParent() |
|
| 476 | 475 |
graph.walkAll(func(image *image.Image) {
|
| 477 | 476 |
// If it's not in the byParent lookup table, then |
| 478 | 477 |
// it's not a parent -> so it's a head! |
| 479 |
- if _, exists := byParent[image.ID]; !exists {
|
|
| 478 |
+ if !graph.HasChildren(image.ID) {
|
|
| 480 | 479 |
heads[image.ID] = image |
| 481 | 480 |
} |
| 482 | 481 |
}) |
| ... | ... |
@@ -51,7 +51,6 @@ func (s *DockerSuite) TestImagesEnsureImageWithBadTagIsNotListed(c *check.C) {
|
| 51 | 51 |
if strings.Contains(out, "busybox") {
|
| 52 | 52 |
c.Fatal("images should not have listed busybox")
|
| 53 | 53 |
} |
| 54 |
- |
|
| 55 | 54 |
} |
| 56 | 55 |
|
| 57 | 56 |
func (s *DockerSuite) TestImagesOrderedByCreationDate(c *check.C) {
|
| ... | ... |
@@ -204,3 +203,42 @@ func (s *DockerSuite) TestImagesWithIncorrectFilter(c *check.C) {
|
| 204 | 204 |
c.Assert(err, check.NotNil) |
| 205 | 205 |
c.Assert(out, checker.Contains, "Invalid filter") |
| 206 | 206 |
} |
| 207 |
+ |
|
| 208 |
+func (s *DockerSuite) TestImagesEnsureOnlyHeadsImagesShown(c *check.C) {
|
|
| 209 |
+ testRequires(c, DaemonIsLinux) |
|
| 210 |
+ |
|
| 211 |
+ dockerfile := ` |
|
| 212 |
+ FROM scratch |
|
| 213 |
+ MAINTAINER docker |
|
| 214 |
+ ENV foo bar` |
|
| 215 |
+ |
|
| 216 |
+ head, out, err := buildImageWithOut("scratch-image", dockerfile, false)
|
|
| 217 |
+ c.Assert(err, check.IsNil) |
|
| 218 |
+ |
|
| 219 |
+ split := strings.Split(out, "\n") |
|
| 220 |
+ intermediate := strings.TrimSpace(split[5][7:]) |
|
| 221 |
+ |
|
| 222 |
+ out, _ = dockerCmd(c, "images") |
|
| 223 |
+ if strings.Contains(out, intermediate) {
|
|
| 224 |
+ c.Fatalf("images shouldn't show non-heads images, got %s in %s", intermediate, out)
|
|
| 225 |
+ } |
|
| 226 |
+ if !strings.Contains(out, head[:12]) {
|
|
| 227 |
+ c.Fatalf("images should contain final built images, want %s in out, got %s", head[:12], out)
|
|
| 228 |
+ } |
|
| 229 |
+} |
|
| 230 |
+ |
|
| 231 |
+func (s *DockerSuite) TestImagesEnsureImagesFromScratchShown(c *check.C) {
|
|
| 232 |
+ testRequires(c, DaemonIsLinux) |
|
| 233 |
+ |
|
| 234 |
+ dockerfile := ` |
|
| 235 |
+ FROM scratch |
|
| 236 |
+ MAINTAINER docker` |
|
| 237 |
+ |
|
| 238 |
+ id, _, err := buildImageWithOut("scratch-image", dockerfile, false)
|
|
| 239 |
+ c.Assert(err, check.IsNil) |
|
| 240 |
+ |
|
| 241 |
+ out, _ := dockerCmd(c, "images") |
|
| 242 |
+ if !strings.Contains(out, id[:12]) {
|
|
| 243 |
+ c.Fatalf("images should contain images built from scratch (e.g. %s), got %s", id[:12], out)
|
|
| 244 |
+ } |
|
| 245 |
+} |
| ... | ... |
@@ -284,3 +284,15 @@ RUN echo 2 #layer2 |
| 284 | 284 |
// should be allowed to untag with the -f flag |
| 285 | 285 |
c.Assert(out, checker.Contains, fmt.Sprintf("Untagged: %s:latest", newTag))
|
| 286 | 286 |
} |
| 287 |
+ |
|
| 288 |
+func (*DockerSuite) TestRmiParentImageFail(c *check.C) {
|
|
| 289 |
+ testRequires(c, DaemonIsLinux) |
|
| 290 |
+ |
|
| 291 |
+ parent, err := inspectField("busybox", "Parent")
|
|
| 292 |
+ c.Assert(err, check.IsNil) |
|
| 293 |
+ out, _, err := dockerCmdWithError("rmi", parent)
|
|
| 294 |
+ c.Assert(err, check.NotNil) |
|
| 295 |
+ if !strings.Contains(out, "image has dependent child images") {
|
|
| 296 |
+ c.Fatalf("rmi should have failed because it's a parent image, got %s", out)
|
|
| 297 |
+ } |
|
| 298 |
+} |