func (r *Remote) FetchID(u *url.URL) (layercake.ID, error) { _, manifest, err := r.manifest(r.Logger.Session("fetch-id"), u) if err != nil { return nil, err } return layercake.DockerImageID(hex(manifest.Layers[len(manifest.Layers)-1].StrongID)), nil }
func (g *OvenCleaner) removeRecursively(log lager.Logger, cake layercake.Cake, id layercake.ID) error { log = log.Session("remove-recursively", lager.Data{"id": id}) log.Debug("start") defer log.Debug("finished") if g.retainCheck.Check(id) { log.Debug("layer-is-held") return nil } img, err := cake.Get(id) if err != nil { log.Error("get-image-failed", err) return nil } if img.Container != "" { log.Debug("image-is-container", lager.Data{"id": id, "container": img.Container}) return nil } if err := cake.Remove(id); err != nil { log.Error("remove-image-failed", err) return err } if img.Parent == "" { log.Debug("stop-image-has-no-parent") return nil } if leaf, err := cake.IsLeaf(layercake.DockerImageID(img.Parent)); err == nil && leaf { log.Debug("has-parent-leaf", lager.Data{"parent-id": img.Parent}) return g.removeRecursively(log, cake, layercake.DockerImageID(img.Parent)) } return nil }
func (r *Remote) fetchLayer(log lager.Logger, conn distclient.Conn, layer distclient.Layer) error { log = log.Session("fetch-layer", lager.Data{"blobsum": layer.BlobSum, "id": layer.StrongID, "parent": layer.ParentStrongID}) log.Info("start") defer log.Info("fetched") r.FetchLock.Acquire(layer.BlobSum.String()) defer r.FetchLock.Release(layer.BlobSum.String()) _, err := r.Cake.Get(layercake.DockerImageID(hex(layer.StrongID))) if err == nil { log.Info("got-cache") return nil } blob, err := conn.GetBlobReader(r.Logger, layer.BlobSum) if err != nil { return err } log.Debug("verifying") verifiedBlob, err := r.Verifier.Verify(blob, layer.BlobSum) if err != nil { return err } log.Debug("verified") defer verifiedBlob.Close() log.Debug("registering") err = r.Cake.Register(&image.Image{ ID: hex(layer.StrongID), Parent: hex(layer.ParentStrongID), Size: layer.Image.Size, }, verifiedBlob) if err != nil { return err } return nil }
func (provider *ContainerLayerCreator) Create(log lager.Logger, id string, parentImage *repository_fetcher.Image, spec Spec) (string, []string, error) { var err error var imageID layercake.ID = layercake.DockerImageID(parentImage.ImageID) if spec.Namespaced { provider.mutex.Lock() imageID, err = provider.namespace(log, imageID) provider.mutex.Unlock() if err != nil { return "", nil, err } } containerID := layercake.ContainerID(id) if err := provider.graph.Create(containerID, imageID, id); err != nil { return "", nil, err } var rootPath string if spec.QuotaSize > 0 && spec.QuotaScope == garden.DiskLimitScopeExclusive { rootPath, err = provider.graph.QuotaedPath(containerID, spec.QuotaSize) } else if spec.QuotaSize > 0 && spec.QuotaScope == garden.DiskLimitScopeTotal { rootPath, err = provider.graph.QuotaedPath(containerID, spec.QuotaSize-parentImage.Size) } else { rootPath, err = provider.graph.Path(containerID) } if err != nil { return "", nil, err } for _, v := range parentImage.Volumes { if err = provider.volumeCreator.Create(rootPath, v); err != nil { return "", nil, err } } return rootPath, parentImage.Env, nil }
func (a *AUFSBaseSizer) BaseSize(logger lager.Logger, containerRootFSPath string) (uint64, error) { var size uint64 graphID := path.Base(containerRootFSPath) for graphID != "" { img, err := a.cake.Get(layercake.DockerImageID(graphID)) if err != nil { return 0, fmt.Errorf("base-size %s: %s", graphID, err) } logger.Debug("base-size", lager.Data{ "layer": graphID, "size": img.Size, "total-size": size, }) size += uint64(img.Size) graphID = img.Parent } return size, nil }
func (u UnderscoreIDer) ProvideID(path string) layercake.ID { return layercake.DockerImageID(strings.Replace(path, "/", "_", -1)) }
// default to not containing an image fakeCake.GetReturns(nil, errors.New("no image")) }) JustBeforeEach(func() { fetcher = &repository_fetcher.Local{ Cake: fakeCake, IDProvider: idProvider, DefaultRootFSPath: defaultRootFSPath, } }) Describe("FetchID", func() { It("delegates to the IDProvider", func() { Expect(fetcher.FetchID(&url.URL{Path: "/something/something"})).To(Equal(layercake.DockerImageID("_something_something"))) }) }) Context("when the image already exists in the graph", func() { It("returns the image id", func() { fakeCake.GetReturns(&image.Image{}, nil) rootFSPath, err := ioutil.TempDir("", "testdir") Expect(err).NotTo(HaveOccurred()) rootFSPath = path.Join(rootFSPath, "foo_bar_baz") Expect(os.MkdirAll(rootFSPath, 0600)).To(Succeed()) response, err := fetcher.Fetch(&url.URL{Path: rootFSPath}, 0) Expect(err).NotTo(HaveOccurred())
JustBeforeEach(func() { gc = cleaner.NewOvenCleaner( retainer, fakeThreshold, ) }) Context("when the threshold is exceeded", func() { BeforeEach(func() { fakeThreshold.ExceededReturns(true) }) Describe("GC", func() { Context("when there is a single leaf", func() { BeforeEach(func() { fakeCake.GetAllLeavesReturns([]layercake.ID{layercake.DockerImageID("child")}, nil) size[layercake.DockerImageID("child2")] = 2048 }) It("should not remove it when it is used by a container", func() { fakeCake.GetReturns(&image.Image{Container: "used-by-me"}, nil) Expect(gc.GC(logger, fakeCake)).To(Succeed()) Expect(fakeCake.RemoveCallCount()).To(Equal(0)) }) Context("when the layer has no parents", func() { BeforeEach(func() { fakeCake.GetReturns(&image.Image{}, nil) }) It("removes the layer", func() {
}) Context("when removig the backing store file fails", func() { BeforeEach(func() { fakeBackingStoreMgr.DeleteReturns(errors.New("banana")) }) It("should return an error", func() { Expect(driver.Put("banana-shed")).To(MatchError("removing the backing store: banana")) }) }) }) Describe("GetMntPath", func() { It("returns the mnt path of the given layer (without calling Path)", func() { Expect(driver.GetMntPath(layercake.DockerImageID("foo"))).To(Equal("/path/to/my/banana/graph/aufs/mnt/foo")) }) }) Describe("GetDiffLayerPath", func() { It("replaces the `/mnt/ substring to `/diff/ in the given path", func() { path := "some/mnt/path" Expect(driver.GetDiffLayerPath(path)).To(Equal("some/diff/path")) }) It("only replaces the first occurance of `/mnt/` to `/diff/` in the given path", func() { path := "some/mnt/mnt/path" Expect(driver.GetDiffLayerPath(path)).To(Equal("some/diff/mnt/path")) }) }) })
) BeforeEach(func() { fakeGraphRetainer = new(fake_retainer.FakeRetainer) fakeDirRootfsProvider = new(fake_container_id_provider.FakeContainerIDProvider) fakeRemoteImageIDProvider = new(fakes.FakeRemoteImageIDFetcher) fakeDirRootfsProvider.ProvideIDStub = func(id string) layercake.ID { return layercake.LocalImageID{ Path: id, ModifiedTime: time.Time{}, } } fakeRemoteImageIDProvider.FetchIDStub = func(id *url.URL) (layercake.ID, error) { return layercake.DockerImageID("/fetched/" + id.Path), nil } imageRetainer = &repository_fetcher.ImageRetainer{ DirectoryRootfsIDProvider: fakeDirRootfsProvider, DockerImageIDFetcher: fakeRemoteImageIDProvider, GraphRetainer: fakeGraphRetainer, NamespaceCacheKey: "chip-sandwhich", Logger: lagertest.NewTestLogger("test"), } }) Context("when a single image is passed", func() { Context("and it is a directory rootfs", func() { It("retains the image", func() {
p, err = cake.Path(id) Expect(err).NotTo(HaveOccurred()) Expect(path.Join(p, "foo")).To(BeAnExistingFile()) }) It("can get back the image", func() { img, err := cake.Get(id) Expect(err).NotTo(HaveOccurred()) Expect(img.ID).To(Equal(id.GraphID())) Expect(img.Parent).To(Equal(parent.GraphID())) }) } Context("when the new layer is a docker image", func() { JustBeforeEach(func() { id = layercake.DockerImageID("70d8f0edf5c9008eb61c7c52c458e7e0a831649dbb238b93dde0854faae314a8") registerImageLayer(cake, &image.Image{ ID: id.GraphID(), Parent: parent.GraphID(), }) }) Context("without a parent", func() { ItCanReadWriteTheLayer() It("can read the files in the image", func() { p, err := cake.Path(id) Expect(err).NotTo(HaveOccurred()) Expect(path.Join(p, id.GraphID())).To(BeAnExistingFile()) })
logger lager.Logger ) BeforeEach(func() { logger = lagertest.NewTestLogger("test") fakeCake = new(fake_cake.FakeCake) fakeCake.GetReturns(nil, errors.New("no such image")) baseSizer = quota_manager.NewAUFSBaseSizer(fakeCake) }) It("asks for the size of the layer based on the base name of the rootfs path", func() { baseSizer.BaseSize(logger, "/some/path/to/54321") Expect(fakeCake.GetCallCount()).To(Equal(1)) Expect(fakeCake.GetArgsForCall(0)).To(Equal(layercake.DockerImageID("54321"))) }) Context("when the layer doesn't exist", func() { It("returns an error", func() { _, err := baseSizer.BaseSize(logger, "/i/dont/exist") Expect(err).To(HaveOccurred()) }) }) Context("when the layer exists", func() { Context("and has no parents", func() { It("returns the size of the layer", func() { fakeCake.GetReturns(&image.Image{ Size: 1234, }, nil)
"some-id", &repository_fetcher.Image{ ImageID: "some-image-id", Env: []string{"env1=env1value", "env2=env2value"}, }, rootfs_provider.Spec{ Namespaced: false, QuotaSize: 0, }, ) Expect(err).ToNot(HaveOccurred()) Expect(fakeCake.CreateCallCount()).To(Equal(1)) id, parent, containerID := fakeCake.CreateArgsForCall(0) Expect(id).To(Equal(layercake.ContainerID("some-id"))) Expect(parent).To(Equal(layercake.DockerImageID("some-image-id"))) Expect(containerID).To(Equal("some-id")) Expect(mountpoint).To(Equal("/some/graph/driver/mount/point")) Expect(envvars).To(Equal( []string{ "env1=env1value", "env2=env2value", }, )) }) }) Context("when the quota is positive", func() { It("should return the quotaed mount point path", func() { quotaedPath := "/path/to/quotaed/bananas"
}) }) Describe("Copying", func() { Context("when parent layer has a file", func() { BeforeEach(func() { Expect(ioutil.WriteFile(filepath.Join(parentDir, "somefile"), []byte("somecontents"), 0755)).To(Succeed()) }) It("should copy the parent layer to the child layer", func() { Expect(aufsCake.Create(namespacedChildID, parentID, "")).To(Succeed()) Expect(cake.CreateCallCount()).To(Equal(1)) layerID, layerParentID, _ := cake.CreateArgsForCall(0) Expect(layerID).To(Equal(namespacedChildID)) Expect(layerParentID).To(Equal(layercake.DockerImageID(""))) Expect(cake.GetCallCount()).To(Equal(1)) Expect(cake.GetArgsForCall(0)).To(Equal(namespacedChildID)) Expect(cake.PathCallCount()).To(Equal(2)) Expect(cake.PathArgsForCall(0)).To(Equal(parentID)) Expect(cake.PathArgsForCall(1)).To(Equal(namespacedChildID)) _, err := os.Stat(filepath.Join(namespacedChildDir, "somefile")) Expect(err).ToNot(HaveOccurred()) }) }) Context("when parent layer has a directory", func() { var subDirectory string
import ( "errors" "code.cloudfoundry.org/garden" "code.cloudfoundry.org/garden-shed/layercake" "code.cloudfoundry.org/lager" "code.cloudfoundry.org/lager/lagertest" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Metrics Adapter", func() { It("converts metrics calls using ID on to GetUsage calls using path", func() { mAdapter := MetricsAdapter{ fn: func(logger lager.Logger, rootfsPath string) (garden.ContainerDiskStat, error) { Expect(rootfsPath).To(Equal("/foo/bar/banana")) return garden.ContainerDiskStat{ TotalBytesUsed: 12, }, errors.New("potato") }, id2path: func(id layercake.ID) string { return "/foo/bar/" + id.GraphID() }, } stat, err := mAdapter.Metrics(lagertest.NewTestLogger("test"), layercake.DockerImageID("banana")) Expect(err).To(MatchError("potato")) Expect(stat.TotalBytesUsed).To(BeEquivalentTo(12)) }) })
_, err := remote.Fetch(parseURL("docker:///foo"), 67) Expect(err).NotTo(HaveOccurred()) _, tag := fakeConn.GetManifestArgsForCall(0) Expect(tag).To(Equal("latest")) }) }) It("returns an image with the ID of the top layer", func() { img, _ := remote.Fetch(parseURL("docker:///foo#some-tag"), 67) Expect(img.ImageID).To(Equal("klm-id")) }) It("can fetch just the ID", func() { id, _ := remote.FetchID(parseURL("docker:///foo#some-tag")) Expect(id).To(Equal(layercake.DockerImageID("klm-id"))) }) It("combines all the environment variable arrays together", func() { img, _ := remote.Fetch(parseURL("docker:///foo#some-tag"), 67) Expect(img.Env).To(ConsistOf([]string{"a", "b", "d", "e", "f"})) }) It("combines all the volumes together", func() { img, _ := remote.Fetch(parseURL("docker:///foo#some-tag"), 67) Expect(img.Volumes).To(ConsistOf([]string{"vol1", "vol2"})) }) It("should verify the image against its digest", func() { remote.Fetch(parseURL("docker:///foo#some-tag"), 67) _, reader := fakeCake.RegisterArgsForCall(0)