// DeleteImage deletes an image from a store func (h *StorageHandlersImpl) DeleteImage(params storage.DeleteImageParams) middleware.Responder { ferr := func(err error, code int) middleware.Responder { log.Errorf("DeleteImage: error %s", err.Error()) return storage.NewDeleteImageDefault(code).WithPayload( &models.Error{ Code: swag.Int64(int64(code)), Message: err.Error(), }) } imageURL, err := util.ImageURL(params.StoreName, params.ID) if err != nil { return ferr(err, http.StatusInternalServerError) } image, err := spl.Parse(imageURL) if err != nil { return ferr(err, http.StatusInternalServerError) } op := trace.NewOperation(context.Background(), fmt.Sprintf("DeleteImage(%s)", image.ID)) if err = h.imageCache.DeleteImage(op, image); err != nil { switch { case spl.IsErrImageInUse(err): return ferr(err, http.StatusLocked) case os.IsNotExist(err): return ferr(err, http.StatusNotFound) default: return ferr(err, http.StatusInternalServerError) } } return storage.NewDeleteImageOK() }
// Creates a tar archive in memory for each layer and uses this to test image creation of layers func TestCreateImageLayers(t *testing.T) { numLayers := 4 cacheStore, client, parentPath, err := setup(t) if !assert.NoError(t, err) { return } vsStore := cacheStore.DataStore.(*ImageStore) defer cleanup(t, client, vsStore, parentPath) op := trace.NewOperation(context.Background(), "test") storeURL, err := cacheStore.CreateImageStore(op, "testStore") if !assert.NoError(t, err) { return } // Get an image that doesn't exist and check for error grbg, err := cacheStore.GetImage(op, storeURL, "garbage") if !assert.Error(t, err) || !assert.Nil(t, grbg) { return } // base this image off scratch parent, err := cacheStore.GetImage(op, storeURL, portlayer.Scratch.ID) if !assert.NoError(t, err) { return } // Keep a list of all files we're extracting via layers so we can verify // they exist in the leaf layer. Ext adds lost+found, so add it here. expectedFilesOnDisk := []string{"lost+found"} // Keep a list of images we created expectedImages := make(map[string]*portlayer.Image) expectedImages[parent.ID] = parent for layer := 0; layer < numLayers; layer++ { dirName := fmt.Sprintf("dir%d", layer) // Add some files to the archive. var files = []tarFile{ {dirName, tar.TypeDir, ""}, {dirName + "/readme.txt", tar.TypeReg, "This archive contains some text files."}, {dirName + "/gopher.txt", tar.TypeReg, "Gopher names:\nGeorge\nGeoffrey\nGonzo"}, {dirName + "/todo.txt", tar.TypeReg, "Get animal handling license."}, } for _, i := range files { expectedFilesOnDisk = append(expectedFilesOnDisk, i.Name) } // meta for the image meta := make(map[string][]byte) meta[dirName+"_meta"] = []byte("Some Meta") meta[dirName+"_moreMeta"] = []byte("Some More Meta") meta[dirName+"_scorpions"] = []byte("Here I am, rock you like a hurricane") // Tar the files buf, terr := tarFiles(files) if !assert.NoError(t, terr) { return } // Calculate the checksum h := sha256.New() h.Write(buf.Bytes()) sum := fmt.Sprintf("sha256:%x", h.Sum(nil)) // Write the image via the cache (which writes to the vsphere impl) writtenImage, terr := cacheStore.WriteImage(op, parent, dirName, meta, sum, buf) if !assert.NoError(t, terr) || !assert.NotNil(t, writtenImage) { return } expectedImages[dirName] = writtenImage // Get the image directly via the vsphere image store impl. vsImage, terr := vsStore.GetImage(op, parent.Store, dirName) if !assert.NoError(t, terr) || !assert.NotNil(t, vsImage) { return } assert.Equal(t, writtenImage, vsImage) // make the next image a child of the one we just created parent = writtenImage } // Test list images on the datastore listedImages, err := vsStore.ListImages(op, parent.Store, nil) if !assert.NoError(t, err) || !assert.NotNil(t, listedImages) { return } for _, img := range listedImages { if !assert.Equal(t, expectedImages[img.ID], img) { return } } // verify the disk's data by attaching the last layer rdonly roDisk, err := mountLayerRO(vsStore, parent) if !assert.NoError(t, err) { return } p, err := roDisk.MountPath() if !assert.NoError(t, err) { return } rodiskcleanupfunc := func() { if roDisk != nil { if roDisk.Mounted() { roDisk.Unmount() } if roDisk.Attached() { vsStore.dm.Detach(op, roDisk) } } os.RemoveAll(p) } filesFoundOnDisk := []string{} // Diff the contents of the RO file of the last child (with all of the contents) err = filepath.Walk(p, func(path string, info os.FileInfo, err error) error { if err != nil { return err } f := path[len(p):] if f != "" { // strip the slash filesFoundOnDisk = append(filesFoundOnDisk, f[1:]) } return nil }) if !assert.NoError(t, err) { return } rodiskcleanupfunc() sort.Strings(filesFoundOnDisk) sort.Strings(expectedFilesOnDisk) if !assert.Equal(t, expectedFilesOnDisk, filesFoundOnDisk) { return } // Try to delete an intermediate image (should fail) exec.NewContainerCache() err = cacheStore.DeleteImage(op, expectedImages["dir1"]) if !assert.Error(t, err) || !assert.True(t, portlayer.IsErrImageInUse(err)) { return } // Try to delete a leaf (should pass) leaf := expectedImages["dir"+strconv.Itoa(numLayers-1)] err = cacheStore.DeleteImage(op, leaf) if !assert.NoError(t, err) { return } // Get the delete image directly via the vsphere image store impl. deletedImage, err := vsStore.GetImage(op, parent.Store, leaf.ID) if !assert.Error(t, err) || !assert.Nil(t, deletedImage) || !assert.True(t, os.IsNotExist(err)) { return } }