func TestCreateImageStore(t *testing.T) { storageImageLayer = spl.NewLookupCache(&MockDataStore{}) s := &StorageHandlersImpl{} store := &models.ImageStore{ Name: "testStore", } params := &storage.CreateImageStoreParams{ Body: store, } result := s.CreateImageStore(*params) if !assert.NotNil(t, result) { return } // try to recreate the same image store result = s.CreateImageStore(*params) if !assert.NotNil(t, result) { return } // expect 409 since it already exists conflict := &storage.CreateImageStoreConflict{ Payload: &models.Error{ Code: swag.Int64(http.StatusConflict), Message: "An image store with that name already exists", }, } if !assert.Equal(t, conflict, result) { return } }
func setup(t *testing.T) (*portlayer.NameLookupCache, *session.Session, string, error) { logrus.SetLevel(logrus.DebugLevel) client := datastore.Session(context.TODO(), t) if client == nil { return nil, nil, "", fmt.Errorf("skip") } storeURL := &url.URL{ Path: datastore.TestName("imageTests"), Host: client.DatastorePath} op := trace.NewOperation(context.Background(), "setup") vsImageStore, err := NewImageStore(op, client, storeURL) if err != nil { if err.Error() == "can't find the hosting vm" { t.Skip("Skipping: test must be run in a VM") } return nil, nil, "", err } s := portlayer.NewLookupCache(vsImageStore) return s, client, storeURL.Path, nil }
func setup(t *testing.T) (*portlayer.NameLookupCache, *session.Session, error) { logrus.SetLevel(logrus.DebugLevel) StorageParentDir = datastore.TestName("imageTests") client := datastore.Session(context.TODO(), t) if client == nil { return nil, nil, fmt.Errorf("skip") } storeURL := &url.URL{ Path: StorageParentDir, Host: client.DatastorePath} vsImageStore, err := NewImageStore(context.TODO(), client, storeURL) if err != nil { if err.Error() == "can't find the hosting vm" { t.Skip("Skipping: test must be run in a VM") } return nil, nil, err } s := portlayer.NewLookupCache(vsImageStore) return s, client, nil }
func TestWriteImage(t *testing.T) { storageImageLayer = spl.NewLookupCache(&MockDataStore{}) // create image store _, err := storageImageLayer.CreateImageStore(context.TODO(), testStoreName) if err != nil { return } s := &StorageHandlersImpl{} 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, } expected := &storage.WriteImageCreated{ Payload: &models.Image{ ID: testImageID, Parent: nil, Store: testStoreURL.String(), Metadata: eMeta, SelfLink: nil, }, } result := s.WriteImage(*params) if !assert.NotNil(t, result) { return } if !assert.Equal(t, expected, result) { return } }
// Configure assigns functions to all the storage api handlers func (handler *StorageHandlersImpl) Configure(api *operations.PortLayerAPI, handlerCtx *HandlerContext) { var err error ctx := context.Background() sessionconfig := &session.Config{ Service: options.PortLayerOptions.SDK, Insecure: options.PortLayerOptions.Insecure, Keepalive: options.PortLayerOptions.Keepalive, DatacenterPath: options.PortLayerOptions.DatacenterPath, ClusterPath: options.PortLayerOptions.ClusterPath, PoolPath: options.PortLayerOptions.PoolPath, DatastorePath: options.PortLayerOptions.DatastorePath, } storageSession, err := session.NewSession(sessionconfig).Create(ctx) if err != nil { log.Fatalf("StorageHandler ERROR: %s", err) } if len(spl.Config.ImageStores) == 0 { log.Panicf("No image stores provided; unable to instantiate storage layer") } imageStoreURL := spl.Config.ImageStores[0] // TODO: support multiple image stores. Right now we only support the first one if len(spl.Config.ImageStores) > 1 { log.Warningf("Multiple image stores found. Multiple image stores are not yet supported. Using [%s] %s", imageStoreURL.Host, imageStoreURL.Path) } ds, err := vsphereSpl.NewImageStore(ctx, storageSession, &imageStoreURL) if err != nil { log.Panicf("Cannot instantiate storage layer: %s", err) } // The imagestore is implemented via a cache which is backed via an // implementation that writes to disks. The cache is used to avoid // expensive metadata lookups. storageImageLayer = spl.NewLookupCache(ds) vsVolumeStore, err := vsphereSpl.NewVolumeStore(context.TODO(), storageSession) if err != nil { log.Panicf("Cannot instantiate the volume store: %s", err) } // Get the datastores for volumes. // Each volume store name maps to a datastore + path, which can be referred to by the name. dstores, err := datastore.GetDatastores(context.TODO(), storageSession, spl.Config.VolumeLocations) if err != nil { log.Panicf("Cannot find datastores: %s", err) } // Add datastores to the vsphere volume store impl for volStoreName, volDatastore := range dstores { log.Infof("Adding volume store %s (%s)", volStoreName, volDatastore.RootURL) _, err := vsVolumeStore.AddStore(context.TODO(), volDatastore, volStoreName) if err != nil { log.Errorf("volume addition error %s", err) } } storageVolumeLayer, err = spl.NewVolumeLookupCache(context.TODO(), vsVolumeStore) if err != nil { log.Panicf("Cannot instantiate the Volume Lookup cache: %s", err) } api.StorageCreateImageStoreHandler = storage.CreateImageStoreHandlerFunc(handler.CreateImageStore) api.StorageGetImageHandler = storage.GetImageHandlerFunc(handler.GetImage) api.StorageGetImageTarHandler = storage.GetImageTarHandlerFunc(handler.GetImageTar) api.StorageListImagesHandler = storage.ListImagesHandlerFunc(handler.ListImages) api.StorageWriteImageHandler = storage.WriteImageHandlerFunc(handler.WriteImage) api.StorageVolumeStoresListHandler = storage.VolumeStoresListHandlerFunc(handler.VolumeStoresList) api.StorageCreateVolumeHandler = storage.CreateVolumeHandlerFunc(handler.CreateVolume) api.StorageRemoveVolumeHandler = storage.RemoveVolumeHandlerFunc(handler.RemoveVolume) api.StorageVolumeJoinHandler = storage.VolumeJoinHandlerFunc(handler.VolumeJoin) api.StorageListVolumesHandler = storage.ListVolumesHandlerFunc(handler.VolumesList) }
func TestListImages(t *testing.T) { storageImageLayer = spl.NewLookupCache(&MockDataStore{}) s := &StorageHandlersImpl{} params := &storage.ListImagesParams{ StoreName: testStoreName, } // expect 404 if image store doesn't exist notFound := &storage.ListImagesNotFound{ Payload: &models.Error{ Code: swag.Int64(http.StatusNotFound), Message: fmt.Sprintf("store (%s) doesn't exist", testStoreURL.String()), }, } outImages := s.ListImages(*params) if !assert.NotNil(t, outImages) { return } if !assert.Equal(t, notFound, outImages) { return } // create the image store url, err := storageImageLayer.CreateImageStore(context.TODO(), testStoreName) if !assert.NoError(t, err) { return } if !assert.NotNil(t, url) { return } // create a set of images images := make(map[string]*spl.Image) parent := spl.Scratch parent.Store = &testStoreURL for i := 1; i < 50; i++ { id := fmt.Sprintf("id-%d", i) img, err := storageImageLayer.WriteImage(context.TODO(), &parent, id, nil, testImageSum, nil) if !assert.NoError(t, err) { return } if !assert.NotNil(t, img) { return } images[id] = img } // List all images outImages = s.ListImages(*params) assert.IsType(t, &storage.ListImagesOK{}, outImages) assert.Equal(t, len(outImages.(*storage.ListImagesOK).Payload), len(images)) for _, img := range outImages.(*storage.ListImagesOK).Payload { _, ok := images[img.ID] if !assert.True(t, ok) { return } } // List specific images var ids []string // query for odd-numbered image ids for i := 1; i < 50; i += 2 { ids = append(ids, fmt.Sprintf("id-%d", i)) } params.Ids = ids outImages = s.ListImages(*params) assert.IsType(t, &storage.ListImagesOK{}, outImages) assert.Equal(t, len(outImages.(*storage.ListImagesOK).Payload), len(ids)) outmap := make(map[string]*models.Image) for _, image := range outImages.(*storage.ListImagesOK).Payload { outmap[image.ID] = image } // ensure no even-numbered image ids in our result for i := 2; i < 50; i += 2 { id := fmt.Sprintf("id-%d", i) _, ok := outmap[id] if !assert.False(t, ok) { return } } }
func TestGetImage(t *testing.T) { storageImageLayer = spl.NewLookupCache(&MockDataStore{}) s := &StorageHandlersImpl{} 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 } // create the image store url, err := storageImageLayer.CreateImageStore(context.TODO(), 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, Parent: nil, Store: &testStoreURL, } expectedMeta := make(map[string][]byte) expectedMeta["foo"] = []byte("bar") // add the image to the store image, err := storageImageLayer.WriteImage(context.TODO(), &parent, testImageID, expectedMeta, testImageSum, nil) if !assert.NoError(t, err) || !assert.NotNil(t, image) { return } 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: nil, Parent: nil, Store: testStoreURL.String(), Metadata: eMeta, }, } result = s.GetImage(*params) if !assert.NotNil(t, result) { return } if !assert.Equal(t, expected, result) { return } }
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 } }
// Configure assigns functions to all the storage api handlers func (h *StorageHandlersImpl) Configure(api *operations.PortLayerAPI, handlerCtx *HandlerContext) { var err error ctx := context.Background() op := trace.NewOperation(ctx, "configure") if len(spl.Config.ImageStores) == 0 { log.Panicf("No image stores provided; unable to instantiate storage layer") } imageStoreURL := spl.Config.ImageStores[0] // TODO: support multiple image stores. Right now we only support the first one if len(spl.Config.ImageStores) > 1 { log.Warningf("Multiple image stores found. Multiple image stores are not yet supported. Using [%s] %s", imageStoreURL.Host, imageStoreURL.Path) } ds, err := vsphereSpl.NewImageStore(op, handlerCtx.Session, &imageStoreURL) if err != nil { log.Panicf("Cannot instantiate storage layer: %s", err) } // The imagestore is implemented via a cache which is backed via an // implementation that writes to disks. The cache is used to avoid // expensive metadata lookups. h.imageCache = spl.NewLookupCache(ds) // The same is done for volumes. It's implemented via a cache which writes // to an implementation that takes a datastore to write to. vsVolumeStore, err := vsphereSpl.NewVolumeStore(op, handlerCtx.Session) if err != nil { log.Panicf("Cannot instantiate the volume store: %s", err) } // Get the datastores for volumes. // Each volume store name maps to a datastore + path, which can be referred to by the name. dstores, err := datastore.GetDatastores(context.TODO(), handlerCtx.Session, spl.Config.VolumeLocations) if err != nil { log.Panicf("Cannot find datastores: %s", err) } // Add datastores to the vsphere volume store impl for volStoreName, volDatastore := range dstores { log.Infof("Adding volume store %s (%s)", volStoreName, volDatastore.RootURL) _, err := vsVolumeStore.AddStore(op, volDatastore, volStoreName) if err != nil { log.Errorf("volume addition error %s", err) } } h.volumeCache, err = spl.NewVolumeLookupCache(op, vsVolumeStore) if err != nil { log.Panicf("Cannot instantiate the Volume Lookup cache: %s", err) } api.StorageCreateImageStoreHandler = storage.CreateImageStoreHandlerFunc(h.CreateImageStore) api.StorageGetImageHandler = storage.GetImageHandlerFunc(h.GetImage) api.StorageGetImageTarHandler = storage.GetImageTarHandlerFunc(h.GetImageTar) api.StorageListImagesHandler = storage.ListImagesHandlerFunc(h.ListImages) api.StorageWriteImageHandler = storage.WriteImageHandlerFunc(h.WriteImage) api.StorageDeleteImageHandler = storage.DeleteImageHandlerFunc(h.DeleteImage) api.StorageVolumeStoresListHandler = storage.VolumeStoresListHandlerFunc(h.VolumeStoresList) api.StorageCreateVolumeHandler = storage.CreateVolumeHandlerFunc(h.CreateVolume) api.StorageRemoveVolumeHandler = storage.RemoveVolumeHandlerFunc(h.RemoveVolume) api.StorageVolumeJoinHandler = storage.VolumeJoinHandlerFunc(h.VolumeJoin) api.StorageListVolumesHandler = storage.ListVolumesHandlerFunc(h.VolumesList) api.StorageGetVolumeHandler = storage.GetVolumeHandlerFunc(h.GetVolume) }