func (c *MockDataStore) WriteImage(op trace.Operation, parent *Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*Image, error) { storeName, err := util.ImageStoreName(parent.Store) if err != nil { return nil, err } selflink, err := util.ImageURL(storeName, ID) if err != nil { return nil, err } var parentLink *url.URL if parent.ID != "" { parentLink, err = util.ImageURL(storeName, parent.ID) if err != nil { return nil, err } } i := &Image{ ID: ID, Store: parent.Store, ParentLink: parentLink, SelfLink: selflink, Metadata: meta, } c.db[*parent.Store][ID] = i return i, nil }
func (v *ImageStore) GetImage(ctx context.Context, store *url.URL, ID string) (*portlayer.Image, error) { defer trace.End(trace.Begin(store.String())) storeName, err := util.ImageStoreName(store) if err != nil { return nil, err } imageURL, err := util.ImageURL(storeName, ID) if err != nil { return nil, err } p := v.imageDirPath(storeName, ID) info, err := v.ds.Stat(ctx, p) if err != nil { return nil, err } _, ok := info.(*types.FolderFileInfo) if !ok { return nil, fmt.Errorf("Stat error: image doesn't exist (%s)", p) } // get the metadata metaDataDir := v.imageMetadataDirPath(storeName, ID) meta, err := getMetadata(ctx, v.ds, metaDataDir) if err != nil { return nil, err } var s = *store var parentURL *url.URL parentID := v.parents.Get(ID) if parentID != "" { parentURL, _ = util.ImageURL(storeName, parentID) } newImage := &portlayer.Image{ ID: ID, SelfLink: imageURL, // We're relying on the parent map for this since we don't currently have a // way to get the disk's spec. See VIC #482 for details. Parent: // parent.SelfLink, Store: &s, Parent: parentURL, Metadata: meta, } log.Debugf("Returning image from location %s with parent url %s", newImage.SelfLink, newImage.Parent) return newImage, nil }
func TestImageCopy(t *testing.T) { storeName := "testStore" ID := "testImageID" imageURL, err := util.ImageURL(storeName, ID) if !assert.NoError(t, err) { return } parentURL, err := util.ImageURL(storeName, Scratch.ID) if !assert.NoError(t, err) { return } img, err := Parse(imageURL) if !assert.NoError(t, err) || !assert.NotNil(t, img) { return } storeURL, err := util.ImageStoreNameToURL(storeName) if !assert.NoError(t, err) { return } expected := &Image{ ID: ID, SelfLink: imageURL, ParentLink: parentURL, Store: storeURL, Metadata: map[string][]byte{ "1": {byte(1)}, "2": {byte(2)}, "3": []byte("three"), }, } actual := expected.Copy().(*Image) if !assert.Equal(t, expected, actual) { return } actual.Metadata["4"] = []byte("four") if !assert.NotEqual(t, expected, actual) { return } }
func (v *ImageStore) GetImage(op trace.Operation, store *url.URL, ID string) (*portlayer.Image, error) { defer trace.End(trace.Begin(store.String())) storeName, err := util.ImageStoreName(store) if err != nil { return nil, err } imageURL, err := util.ImageURL(storeName, ID) if err != nil { return nil, err } if err = v.verifyImage(op, storeName, ID); err != nil { return nil, err } // get the metadata metaDataDir := v.imageMetadataDirPath(storeName, ID) meta, err := getMetadata(op, v.ds, metaDataDir) if err != nil { return nil, err } var s = *store var parentURL *url.URL parentID := v.parents.Get(ID) if parentID != "" { parentURL, _ = util.ImageURL(storeName, parentID) } newImage := &portlayer.Image{ ID: ID, SelfLink: imageURL, // We're relying on the parent map for this since we don't currently have a // way to get the disk's spec. See VIC #482 for details. Parent: // parent.SelfLink, Store: &s, ParentLink: parentURL, Metadata: meta, } op.Debugf("Returning image from location %s with parent url %s", newImage.SelfLink, newImage.Parent()) return newImage, nil }
// WriteImage creates a new image layer from the given parent. // Eg parentImage + newLayer = new Image built from parent // // parent - The parent image to create the new image from. // ID - textual ID for the image to be written // meta - metadata associated with the image // Tag - the tag of the image to be written func (v *ImageStore) WriteImage(op trace.Operation, parent *portlayer.Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*portlayer.Image, error) { storeName, err := util.ImageStoreName(parent.Store) if err != nil { return nil, err } imageURL, err := util.ImageURL(storeName, ID) if err != nil { return nil, err } // If this is scratch, then it's the root of the image store. All images // will be descended from this created and prepared fs. if ID == portlayer.Scratch.ID { // Create the scratch layer if err := v.scratch(op, storeName); err != nil { return nil, err } } else { if parent.ID == "" { return nil, fmt.Errorf("parent ID is empty") } // persist the relationship v.parents.Add(ID, parent.ID) if err := v.parents.Save(op); err != nil { return nil, err } if err := v.writeImage(op, storeName, parent.ID, ID, meta, sum, r); err != nil { return nil, err } } newImage := &portlayer.Image{ ID: ID, SelfLink: imageURL, ParentLink: parent.SelfLink, Store: parent.Store, Metadata: meta, } return newImage, nil }
// GetImage gets the specified image from the given store by retreiving it from the cache. func (c *NameLookupCache) GetImage(op trace.Operation, store *url.URL, ID string) (*Image, error) { op.Debugf("Getting image %s from %s", ID, store.String()) storeName, err := util.ImageStoreName(store) if err != nil { return nil, err } // Check the store exists if _, err = c.GetImageStore(op, storeName); err != nil { return nil, err } c.storeCacheLock.Lock() indx := c.storeCache[*store] c.storeCacheLock.Unlock() imgURL, err := util.ImageURL(storeName, ID) if err != nil { return nil, err } node, err := c.storeCache[*store].Get(imgURL.String()) var img *Image if err != nil { if err == index.ErrNodeNotFound { debugf("Image %s not in cache, retreiving from datastore", ID) // Not in the cache. Try to load it. img, err = c.DataStore.GetImage(op, store, ID) if err != nil { return nil, err } if err = indx.Insert(img); err != nil { return nil, err } } else { return nil, err } } else { img, _ = node.(*Image) } return img, nil }
func (c *MockDataStore) WriteImage(op trace.Operation, parent *spl.Image, ID string, meta map[string][]byte, sum string, r io.Reader) (*spl.Image, error) { storeName, err := util.ImageStoreName(parent.Store) if err != nil { return nil, err } selflink, err := util.ImageURL(storeName, ID) if err != nil { return nil, err } i := spl.Image{ ID: ID, Store: parent.Store, ParentLink: parent.SelfLink, SelfLink: selflink, Metadata: meta, } return &i, nil }
// 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() }
func TestWriteImage(t *testing.T) { ic := spl.NewLookupCache(&MockDataStore{}) // create image store op := trace.NewOperation(context.Background(), "test") _, err := ic.CreateImageStore(op, testStoreName) if err != nil { return } s := &StorageHandlersImpl{ imageCache: ic, } eMeta := make(map[string]string) eMeta["foo"] = "bar" name := new(string) val := new(string) *name = "foo" *val = eMeta["foo"] params := &storage.WriteImageParams{ StoreName: testStoreName, ImageID: testImageID, ParentID: "scratch", Sum: testImageSum, Metadatakey: name, Metadataval: val, ImageFile: nil, } parentlink, err := util.ImageURL(testStoreName, params.ParentID) if !assert.NoError(t, err) { return } p := parentlink.String() selflink, err := util.ImageURL(testStoreName, testImageID) if !assert.NoError(t, err) { return } sl := selflink.String() expected := &storage.WriteImageCreated{ Payload: &models.Image{ ID: testImageID, Parent: &p, SelfLink: &sl, Store: testStoreURL.String(), Metadata: eMeta, }, } result := s.WriteImage(*params) if !assert.NotNil(t, result) { return } if !assert.Equal(t, expected, result) { return } }
func TestGetImage(t *testing.T) { s := &StorageHandlersImpl{ imageCache: spl.NewLookupCache(&MockDataStore{}), } params := &storage.GetImageParams{ ID: testImageID, StoreName: testStoreName, } // expect 404 since no image store exists by that name storeNotFound := &storage.GetImageNotFound{ Payload: &models.Error{ Code: swag.Int64(http.StatusNotFound), Message: fmt.Sprintf("store (%s) doesn't exist", testStoreURL.String()), }, } result := s.GetImage(*params) if !assert.NotNil(t, result) { return } if !assert.Equal(t, storeNotFound, result) { return } op := trace.NewOperation(context.Background(), "test") // create the image store url, err := s.imageCache.CreateImageStore(op, testStoreName) // TODO(jzt): these are testing NameLookupCache, do we need them here? if !assert.Nil(t, err, "Error while creating image store") { return } if !assert.Equal(t, testStoreURL.String(), url.String()) { return } // expect 404 since no image exists by that name in that store imageNotFound := &storage.GetImageNotFound{ Payload: &models.Error{ Code: swag.Int64(http.StatusNotFound), Message: fmt.Sprintf("store (%s) doesn't have image %s", testStoreURL.String(), testImageID), }, } // try GetImage again result = s.GetImage(*params) if !assert.NotNil(t, result) { return } if !assert.Equal(t, imageNotFound, result) { return } // add image to store parent := spl.Image{ ID: "scratch", SelfLink: nil, ParentLink: nil, Store: &testStoreURL, } expectedMeta := make(map[string][]byte) expectedMeta["foo"] = []byte("bar") // add the image to the store image, err := s.imageCache.WriteImage(op, &parent, testImageID, expectedMeta, testImageSum, nil) if !assert.NoError(t, err) || !assert.NotNil(t, image) { return } selflink, err := util.ImageURL(testStoreName, testImageID) if !assert.NoError(t, err) { return } sl := selflink.String() parentlink, err := util.ImageURL(testStoreName, parent.ID) if !assert.NoError(t, err) { return } p := parentlink.String() eMeta := make(map[string]string) eMeta["foo"] = "bar" // expect our image back now that we've created it expected := &storage.GetImageOK{ Payload: &models.Image{ ID: image.ID, SelfLink: &sl, Parent: &p, Store: testStoreURL.String(), Metadata: eMeta, }, } result = s.GetImage(*params) if !assert.NotNil(t, result) { return } if !assert.Equal(t, expected, result) { return } }