// ListImages returns a list of images in a store func (handler *StorageHandlersImpl) ListImages(params storage.ListImagesParams) middleware.Responder { u, err := util.ImageStoreNameToURL(params.StoreName) if err != nil { return storage.NewListImagesDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } images, err := storageImageLayer.ListImages(context.TODO(), u, params.Ids) if err != nil { return storage.NewListImagesNotFound().WithPayload( &models.Error{ Code: swag.Int64(http.StatusNotFound), Message: err.Error(), }) } result := make([]*models.Image, 0, len(images)) for _, image := range images { result = append(result, convertImage(image)) } return storage.NewListImagesOK().WithPayload(result) }
// GetImageStore checks to see if a named image store exists and returls the // URL to it if so or error. func (c *MockDataStore) GetImageStore(ctx context.Context, storeName string) (*url.URL, error) { u, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } return nil, fmt.Errorf("store (%s) doesn't exist", u.String()) }
// WriteImage writes an image to an image store func (handler *StorageHandlersImpl) WriteImage(params storage.WriteImageParams) middleware.Responder { u, err := util.ImageStoreNameToURL(params.StoreName) if err != nil { return storage.NewWriteImageDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } parent := &spl.Image{ Store: u, ID: params.ParentID, } var meta map[string][]byte if params.Metadatakey != nil && params.Metadataval != nil { meta = map[string][]byte{*params.Metadatakey: []byte(*params.Metadataval)} } image, err := storageImageLayer.WriteImage(context.TODO(), parent, params.ImageID, meta, params.Sum, params.ImageFile) if err != nil { return storage.NewWriteImageDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } i := convertImage(image) return storage.NewWriteImageCreated().WithPayload(i) }
// GetImageStore checks to see if the image store exists on disk and returns an // error or the store's URL. func (v *ImageStore) GetImageStore(op trace.Operation, storeName string) (*url.URL, error) { u, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } p := v.imageStorePath(storeName) info, err := v.ds.Stat(op, p) if err != nil { return nil, err } _, ok := info.(*types.FolderFileInfo) if !ok { return nil, fmt.Errorf("Stat error: path doesn't exist (%s)", p) } if v.parents == nil { // This is startup. Look for image directories without manifest files and // nuke them. if err := v.cleanup(op, u); err != nil { return nil, err } pm, err := restoreParentMap(op, v.ds, storeName) if err != nil { return nil, err } v.parents = pm } return u, nil }
// WriteImage writes an image to an image store func (h *StorageHandlersImpl) WriteImage(params storage.WriteImageParams) middleware.Responder { u, err := util.ImageStoreNameToURL(params.StoreName) if err != nil { return storage.NewWriteImageDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } parent := &spl.Image{ Store: u, ID: params.ParentID, } var meta map[string][]byte if params.Metadatakey != nil && params.Metadataval != nil { meta = map[string][]byte{*params.Metadatakey: []byte(*params.Metadataval)} } op := trace.NewOperation(context.Background(), fmt.Sprintf("WriteImage(%s)", params.ImageID)) image, err := h.imageCache.WriteImage(op, parent, params.ImageID, meta, params.Sum, params.ImageFile) if err != nil { return storage.NewWriteImageDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } i := convertImage(image) return storage.NewWriteImageCreated().WithPayload(i) }
// ListImages returns a list of images in a store func (h *StorageHandlersImpl) ListImages(params storage.ListImagesParams) middleware.Responder { u, err := util.ImageStoreNameToURL(params.StoreName) if err != nil { return storage.NewListImagesDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } op := trace.NewOperation(context.Background(), fmt.Sprintf("ListImages(%s, %q)", u.String(), params.Ids)) images, err := h.imageCache.ListImages(op, u, params.Ids) if err != nil { return storage.NewListImagesNotFound().WithPayload( &models.Error{ Code: swag.Int64(http.StatusNotFound), Message: err.Error(), }) } result := make([]*models.Image, 0, len(images)) for _, image := range images { result = append(result, convertImage(image)) } return storage.NewListImagesOK().WithPayload(result) }
func Parse(u *url.URL) (*Image, error) { // Check the path isn't malformed. if !filepath.IsAbs(u.Path) { return nil, errors.New("invalid uri path") } segments := strings.Split(filepath.Clean(u.Path), "/") if segments[0] != util.StorageURLPath { return nil, errors.New("not a storage path") } if len(segments) < 3 { return nil, errors.New("uri path mismatch") } store, err := util.ImageStoreNameToURL(segments[2]) if err != nil { return nil, err } id := segments[3] var SelfLink url.URL SelfLink = *u i := &Image{ ID: id, SelfLink: &SelfLink, Store: store, } return i, nil }
func (c *NameLookupCache) CreateImageStore(op trace.Operation, storeName string) (*url.URL, error) { store, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } // Check for existence and rehydrate the cache if it exists on disk. _, err = c.GetImageStore(op, storeName) // we expect this not to exist. if err == nil { return nil, os.ErrExist } c.storeCacheLock.Lock() defer c.storeCacheLock.Unlock() store, err = c.DataStore.CreateImageStore(op, storeName) if err != nil { return nil, err } // Create the root image scratch, err := c.DataStore.WriteImage(op, &Image{Store: store}, Scratch.ID, nil, "", nil) if err != nil { return nil, err } indx := index.NewIndex() c.storeCache[*store] = indx if err = indx.Insert(scratch); err != nil { return nil, err } return store, nil }
func (c *MockDataStore) CreateImageStore(ctx context.Context, storeName string) (*url.URL, error) { u, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } return u, nil }
func (c *MockDataStore) CreateImageStore(op trace.Operation, storeName string) (*url.URL, error) { u, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } return u, 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 } }
// Cache population should be happening in order starting from parent(id1) to children(id4) func TestPopulateCacheInExpectedOrder(t *testing.T) { logrus.SetLevel(logrus.DebugLevel) st := NewMockDataStore() op := trace.NewOperation(context.Background(), "test") storeURL, _ := util.ImageStoreNameToURL("testStore") storageURLStr := storeURL.String() url1, _ := url.Parse(storageURLStr + "/id1") url2, _ := url.Parse(storageURLStr + "/id2") url3, _ := url.Parse(storageURLStr + "/id3") url4, _ := url.Parse(storageURLStr + "/id4") scratchURL, _ := url.Parse(storageURLStr + Scratch.ID) img1 := &Image{ID: "id1", SelfLink: url1, ParentLink: scratchURL, Store: storeURL} img2 := &Image{ID: "id2", SelfLink: url2, ParentLink: url1, Store: storeURL} img3 := &Image{ID: "id3", SelfLink: url3, ParentLink: url2, Store: storeURL} img4 := &Image{ID: "id4", SelfLink: url4, ParentLink: url3, Store: storeURL} scratchImg := &Image{ ID: Scratch.ID, SelfLink: scratchURL, ParentLink: scratchURL, Store: storeURL, } // Order does matter for some reason. imageMap := map[string]*Image{ img1.ID: img1, img4.ID: img4, img2.ID: img2, img3.ID: img3, scratchImg.ID: scratchImg, } st.db[*storeURL] = imageMap imageCache := NewLookupCache(st) imageCache.GetImageStore(op, "testStore") // Check if all images are available. imageIds := []string{"id1", "id2", "id3", "id4"} for _, imageID := range imageIds { v, _ := imageCache.GetImage(op, storeURL, imageID) assert.NotNil(t, v) } }
// GetImageStore checks to see if a named image store exists and returls the // URL to it if so or error. func (c *NameLookupCache) GetImageStore(ctx context.Context, storeName string) (*url.URL, error) { store, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } c.storeCacheLock.Lock() defer c.storeCacheLock.Unlock() // check the cache _, ok := c.storeCache[*store] if !ok { log.Info("Refreshing image cache from datastore.") // Store isn't in the cache. Look it up in the datastore. storeName, err := util.ImageStoreName(store) if err != nil { return nil, err } // If the store doesn't exist, we'll fall out here. _, err = c.DataStore.GetImageStore(ctx, storeName) if err != nil { return nil, err } c.storeCache[*store] = make(map[string]Image) // Fall out here if there are no images. We should at least have a scratch. images, err := c.DataStore.ListImages(ctx, store, nil) if err != nil { return nil, err } // add the images we retrieved to the cache. for _, v := range images { log.Infof("Imagestore: Found image %s on datastore.", v.ID) c.storeCache[*store][v.ID] = *v } // Assert there's a scratch if _, ok = c.storeCache[*store][Scratch.ID]; !ok { return nil, fmt.Errorf("Scratch does not exist. Imagestore is corrrupt.") } } return store, nil }
func (v *ImageStore) CreateImageStore(op trace.Operation, storeName string) (*url.URL, error) { // convert the store name to a port layer url. u, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } if _, err = v.ds.Mkdir(op, true, v.imageStorePath(storeName)); err != nil { return nil, err } if v.parents == nil { pm, err := restoreParentMap(op, v.ds, storeName) if err != nil { return nil, err } v.parents = pm } return u, nil }
// GetImage retrieves an image from a store func (handler *StorageHandlersImpl) GetImage(params storage.GetImageParams) middleware.Responder { id := params.ID url, err := util.ImageStoreNameToURL(params.StoreName) if err != nil { return storage.NewGetImageDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } image, err := storageImageLayer.GetImage(context.TODO(), url, id) if err != nil { e := &models.Error{Code: swag.Int64(http.StatusNotFound), Message: err.Error()} return storage.NewGetImageNotFound().WithPayload(e) } result := convertImage(image) return storage.NewGetImageOK().WithPayload(result) }
func (v *ImageStore) ListImageStores(op trace.Operation) ([]*url.URL, error) { res, err := v.ds.Ls(op, v.imageStorePath("")) if err != nil { return nil, err } stores := []*url.URL{} for _, f := range res.File { folder, ok := f.(*types.FolderFileInfo) if !ok { continue } u, err := util.ImageStoreNameToURL(folder.Path) if err != nil { return nil, err } stores = append(stores, u) } return stores, nil }
// GetImage retrieves an image from a store func (h *StorageHandlersImpl) GetImage(params storage.GetImageParams) middleware.Responder { id := params.ID url, err := util.ImageStoreNameToURL(params.StoreName) if err != nil { return storage.NewGetImageDefault(http.StatusInternalServerError).WithPayload( &models.Error{ Code: swag.Int64(http.StatusInternalServerError), Message: err.Error(), }) } op := trace.NewOperation(context.Background(), fmt.Sprintf("GetImage(%s)", id)) image, err := h.imageCache.GetImage(op, url, id) if err != nil { e := &models.Error{Code: swag.Int64(http.StatusNotFound), Message: err.Error()} return storage.NewGetImageNotFound().WithPayload(e) } result := convertImage(image) return storage.NewGetImageOK().WithPayload(result) }
// GetImageStore checks to see if a named image store exists and returls the // URL to it if so or error. func (c *NameLookupCache) GetImageStore(op trace.Operation, storeName string) (*url.URL, error) { store, err := util.ImageStoreNameToURL(storeName) if err != nil { return nil, err } c.storeCacheLock.Lock() defer c.storeCacheLock.Unlock() // check the cache _, ok := c.storeCache[*store] if !ok { infof("Refreshing image cache from datastore.") // Store isn't in the cache. Look it up in the datastore. storeName, err := util.ImageStoreName(store) if err != nil { return nil, err } // If the store doesn't exist, we'll fall out here. _, err = c.DataStore.GetImageStore(op, storeName) if err != nil { return nil, err } idx := index.NewIndex() c.storeCache[*store] = idx // Add Scratch scratch, err := c.DataStore.GetImage(op, store, Scratch.ID) if err != nil { log.Errorf("ImageCache Error: looking up scratch on %s: %s", store.String(), err) return nil, ErrCorruptImageStore } if err = idx.Insert(scratch); err != nil { return nil, err } // XXX after creating the indx and populating the map, we can put the rest in a go routine // Fall out here if there are no images. We should at least have a scratch. images, err := c.DataStore.ListImages(op, store, nil) if err != nil { return nil, err } debugf("Found %d images", len(images)) // Build image map to simplify tree traversal. imageMap := make(map[string]*Image, len(images)) for _, img := range images { if img.ID == Scratch.ID { continue } imageMap[img.Self()] = img } for k := range imageMap { parentTree(k, idx, imageMap) } } return store, nil }