Пример #1
0
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
}
Пример #2
0
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
}
Пример #3
0
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
}
Пример #4
0
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
}
Пример #5
0
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
}
Пример #6
0
func (u UnderscoreIDer) ProvideID(path string) layercake.ID {
	return layercake.DockerImageID(strings.Replace(path, "/", "_", -1))
}
Пример #7
0
		// 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())
Пример #8
0
	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() {
Пример #9
0
		})

		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() {
Пример #11
0
					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)
Пример #13
0
					"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"
Пример #14
0
				})
			})

			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))
	})
})
Пример #16
0
			_, 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)