func (s *ImageSuite) TestAddImageConcurrent(c *gc.C) { metadata0 := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 1, SHA256: "0", SourceURL: "http://path", } metadata1 := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 1, SHA256: "1", SourceURL: "http://path", } addMetadata := func() { err := s.storage.AddImage(strings.NewReader("0"), metadata0) c.Assert(err, gc.IsNil) managedStorage := imagestorage.ManagedStorage(s.storage, s.session) r, _, err := managedStorage.GetForBucket("my-uuid", "images/lxc-trusty-amd64:0") c.Assert(err, gc.IsNil) r.Close() } defer txntesting.SetBeforeHooks(c, s.txnRunner, addMetadata).Check() err := s.storage.AddImage(strings.NewReader("1"), metadata1) c.Assert(err, gc.IsNil) // Blob added in before-hook should be removed. managedStorage := imagestorage.ManagedStorage(s.storage, s.session) _, _, err = managedStorage.GetForBucket("my-uuid", "images/lxc-trusty-amd64:0") c.Assert(err, jc.Satisfies, errors.IsNotFound) s.assertImage(c, metadata1, "1") }
func (s *ImageSuite) TestDeleteImage(c *gc.C) { s.addMetadataDoc(c, "lxc", "trusty", "amd64", 3, "hash(abc)", "images/lxc-trusty-amd64:sha256", "http://lxc-trusty-amd64") managedStorage := imagestorage.ManagedStorage(s.storage, s.session) err := managedStorage.PutForBucket("my-uuid", "images/lxc-trusty-amd64:sha256", strings.NewReader("blah"), 4) c.Assert(err, gc.IsNil) _, rc, err := s.storage.Image("lxc", "trusty", "amd64") c.Assert(err, gc.IsNil) c.Assert(rc, gc.NotNil) rc.Close() metadata := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", SHA256: "sha256", } err = s.storage.DeleteImage(metadata) c.Assert(err, gc.IsNil) _, _, err = managedStorage.GetForBucket("my-uuid", "images/lxc-trusty-amd64:sha256") c.Assert(err, jc.Satisfies, errors.IsNotFound) _, _, err = s.storage.Image("lxc", "trusty", "amd64") c.Assert(err, jc.Satisfies, errors.IsNotFound) }
func (s *ImageSuite) TestAddImageExcessiveContention(c *gc.C) { metadata := []*imagestorage.Metadata{ {ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 1, SHA256: "0", SourceURL: "http://path"}, {ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 1, SHA256: "1", SourceURL: "http://path"}, {ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 1, SHA256: "2", SourceURL: "http://path"}, {ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 1, SHA256: "3", SourceURL: "http://path"}, } i := 1 addMetadata := func() { err := s.storage.AddImage(strings.NewReader(metadata[i].SHA256), metadata[i]) c.Assert(err, gc.IsNil) i++ } defer txntesting.SetBeforeHooks(c, s.txnRunner, addMetadata, addMetadata, addMetadata).Check() err := s.storage.AddImage(strings.NewReader(metadata[0].SHA256), metadata[0]) c.Assert(err, gc.ErrorMatches, "cannot store image metadata: state changing too quickly; try again soon") // There should be no blobs apart from the last one added by the before-hook. for _, metadata := range metadata[:3] { path := fmt.Sprintf("images/%s-%s-%s:%s", metadata.Kind, metadata.Series, metadata.Arch, metadata.SHA256) managedStorage := imagestorage.ManagedStorage(s.storage, s.session) _, _, err = managedStorage.GetForBucket("my-uuid", path) c.Assert(err, jc.Satisfies, errors.IsNotFound) } s.assertImage(c, metadata[3], "3") }
func (s *ImageSuite) TestAddImageRemovesExistingRemoveFails(c *gc.C) { // Add a metadata doc and a blob at a known path, then // call AddImage and ensure that AddImage attempts to remove // the original blob, but does not return an error if it // fails. s.addMetadataDoc(c, "lxc", "trusty", "amd64", 3, "hash(abc)", "path", "http://path") managedStorage := imagestorage.ManagedStorage(s.storage, s.session) err := managedStorage.PutForBucket("my-uuid", "path", strings.NewReader("blah"), 4) c.Assert(err, gc.IsNil) storage := imagestorage.NewStorage(s.session, "my-uuid") s.PatchValue(imagestorage.GetManagedStorage, imagestorage.RemoveFailsManagedStorage) addedMetadata := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 6, SHA256: "hash(xyzzzz)", SourceURL: "http://path", } err = storage.AddImage(strings.NewReader("xyzzzz"), addedMetadata) c.Assert(err, gc.IsNil) // old blob should still be there r, _, err := managedStorage.GetForBucket("my-uuid", "path") c.Assert(err, gc.IsNil) r.Close() s.assertImage(c, addedMetadata, "xyzzzz") }
func (s *ImageSuite) TestAddImageRemovesExisting(c *gc.C) { // Add a metadata doc and a blob at a known path, then // call AddImage and ensure the original blob is removed. s.addMetadataDoc(c, "lxc", "trusty", "amd64", 3, "hash(abc)", "path", "http://path") managedStorage := imagestorage.ManagedStorage(s.storage, s.session) err := managedStorage.PutForBucket("my-uuid", "path", strings.NewReader("blah"), 4) c.Assert(err, gc.IsNil) addedMetadata := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 6, SHA256: "hash(xyzzzz)", SourceURL: "http://path", } err = s.storage.AddImage(strings.NewReader("xyzzzz"), addedMetadata) c.Assert(err, gc.IsNil) // old blob should be gone _, _, err = managedStorage.GetForBucket("my-uuid", "path") c.Assert(err, jc.Satisfies, errors.IsNotFound) s.assertImage(c, addedMetadata, "xyzzzz") }
func (s *ImageSuite) TestImage(c *gc.C) { _, _, err := s.storage.Image("lxc", "trusty", "amd64") c.Assert(err, jc.Satisfies, errors.IsNotFound) c.Assert(err, gc.ErrorMatches, `.* image metadata not found`) s.addMetadataDoc(c, "lxc", "trusty", "amd64", 3, "hash(abc)", "path", "http://path") _, _, err = s.storage.Image("lxc", "trusty", "amd64") c.Assert(err, jc.Satisfies, errors.IsNotFound) c.Assert(err, gc.ErrorMatches, `resource at path "buckets/my-uuid/path" not found`) managedStorage := imagestorage.ManagedStorage(s.storage, s.session) err = managedStorage.PutForBucket("my-uuid", "path", strings.NewReader("blah"), 4) c.Assert(err, gc.IsNil) metadata, r, err := s.storage.Image("lxc", "trusty", "amd64") c.Assert(err, gc.IsNil) defer r.Close() checkMetadata(c, metadata, &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 3, SHA256: "hash(abc)", SourceURL: "http://path", }) data, err := ioutil.ReadAll(r) c.Assert(err, gc.IsNil) c.Assert(string(data), gc.Equals, "blah") }
func (s *ImageSuite) TestAddImageRemovesBlobOnFailure(c *gc.C) { storage := imagestorage.NewStorage(s.session, "my-uuid") s.txnRunner = errorTransactionRunner{s.txnRunner} addedMetadata := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 6, SHA256: "hash", } err := storage.AddImage(strings.NewReader("xyzzzz"), addedMetadata) c.Assert(err, gc.ErrorMatches, "cannot store image metadata: Run fails") path := fmt.Sprintf( "images/%s-%s-%s:%s", addedMetadata.Kind, addedMetadata.Series, addedMetadata.Arch, addedMetadata.SHA256) managedStorage := imagestorage.ManagedStorage(s.storage, s.session) _, _, err = managedStorage.GetForBucket("my-uuid", path) c.Assert(err, jc.Satisfies, errors.IsNotFound) }
func (s *ImageSuite) TestAddImageRemovesBlobOnFailureRemoveFails(c *gc.C) { storage := imagestorage.NewStorage(s.session, "my-uuid") s.PatchValue(imagestorage.GetManagedStorage, imagestorage.RemoveFailsManagedStorage) s.txnRunner = errorTransactionRunner{s.txnRunner} addedMetadata := &imagestorage.Metadata{ ModelUUID: "my-uuid", Kind: "lxc", Series: "trusty", Arch: "amd64", Size: 6, SHA256: "hash", } err := storage.AddImage(strings.NewReader("xyzzzz"), addedMetadata) c.Assert(err, gc.ErrorMatches, "cannot store image metadata: Run fails") // blob should still be there, because the removal failed. path := fmt.Sprintf( "images/%s-%s-%s:%s", addedMetadata.Kind, addedMetadata.Series, addedMetadata.Arch, addedMetadata.SHA256) managedStorage := imagestorage.ManagedStorage(s.storage, s.session) r, _, err := managedStorage.GetForBucket("my-uuid", path) c.Assert(err, gc.IsNil) r.Close() }