From e1de76d65c2ca8c4ae2172a42d03a53a05dc1eee Mon Sep 17 00:00:00 2001 From: Roberto Jimenez Sanchez Date: Wed, 5 Apr 2017 10:18:04 +0100 Subject: [PATCH] Rootless creation on overlay [finishes #140663715] Signed-off-by: Gareth Clay --- hack/run-tests | 5 + integration/clean_test.go | 4 + integration/create_concurrency_test.go | 2 + integration/create_local_test.go | 28 +++++- integration/create_remote_test.go | 5 + integration/create_test.go | 125 ++++++++++++++----------- integration/delete_test.go | 1 + integration/list_test.go | 1 + integration/metrics_test.go | 2 + integration/runner/create.go | 80 ++++++++++++++-- integration/runner/globals.go | 6 ++ integration/runner/runner.go | 3 +- integration/stats_test.go | 1 + integration/utils.go | 6 ++ 14 files changed, 201 insertions(+), 68 deletions(-) diff --git a/hack/run-tests b/hack/run-tests index 07140346d..3f38632fe 100755 --- a/hack/run-tests +++ b/hack/run-tests @@ -118,6 +118,11 @@ run_all_tests() { export GROOTFS_TEST_GID=0 fly_integration_tests "integration" + export VOLUME_DRIVER="overlay-xfs" + export GROOTFS_TEST_UID=1000 + export GROOTFS_TEST_GID=1000 + fly_integration_tests "integration" + export VOLUME_DRIVER="btrfs" export GROOTFS_TEST_UID=0 export GROOTFS_TEST_GID=0 diff --git a/integration/clean_test.go b/integration/clean_test.go index 8c57e3dc8..60bdcc767 100644 --- a/integration/clean_test.go +++ b/integration/clean_test.go @@ -20,6 +20,10 @@ import ( ) var _ = Describe("Clean", func() { + BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) + }) + Context("Local Images", func() { var ( baseImagePath string diff --git a/integration/create_concurrency_test.go b/integration/create_concurrency_test.go index fd5a5d1f0..85ac7717d 100644 --- a/integration/create_concurrency_test.go +++ b/integration/create_concurrency_test.go @@ -5,6 +5,7 @@ import ( "sync" "code.cloudfoundry.org/grootfs/groot" + "code.cloudfoundry.org/grootfs/integration" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -12,6 +13,7 @@ import ( var _ = Describe("Concurrent creations", func() { BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) // run this to setup the store before concurrency! _, err := Runner.Create(groot.CreateSpec{ ID: "test-pre-warm", diff --git a/integration/create_local_test.go b/integration/create_local_test.go index c99b8d021..9e5e1585c 100644 --- a/integration/create_local_test.go +++ b/integration/create_local_test.go @@ -48,7 +48,8 @@ var _ = Describe("Create with local images", func() { spec = groot.CreateSpec{ BaseImage: baseImagePath, ID: "random-id", - Mount: true, + Mount: mountByDefault(), + Json: true, } }) @@ -56,8 +57,11 @@ var _ = Describe("Create with local images", func() { image, err := Runner.Create(spec) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) + imageContentPath := path.Join(image.Rootfs, "foo") Expect(imageContentPath).To(BeARegularFile()) + fooContents, err := ioutil.ReadFile(imageContentPath) Expect(err).NotTo(HaveOccurred()) Expect(string(fooContents)).To(Equal("hello-world")) @@ -66,6 +70,7 @@ var _ = Describe("Create with local images", func() { It("keeps folders original permissions", func() { image, err := Runner.Create(spec) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) permissiveFolderPath := path.Join(image.Rootfs, "permissive-folder") stat, err := os.Stat(permissiveFolderPath) @@ -81,9 +86,11 @@ var _ = Describe("Create with local images", func() { image2, err := Runner.Create(groot.CreateSpec{ ID: "another-random-id", BaseImage: baseImagePath, - Mount: true, + Mount: false, + Json: true, }) Expect(err).NotTo(HaveOccurred()) + Expect(ioutil.WriteFile(filepath.Join(image1.Rootfs, "new-file"), []byte("hello-world"), 0644)).To(Succeed()) Expect(filepath.Join(image2.Rootfs, "new-file")).NotTo(BeARegularFile()) }) @@ -104,6 +111,7 @@ var _ = Describe("Create with local images", func() { It("preserves the timestamps", func() { image, err := Runner.Create(spec) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) imageOldFilePath := path.Join(image.Rootfs, "old-file") fi, err := os.Stat(imageOldFilePath) @@ -114,10 +122,12 @@ var _ = Describe("Create with local images", func() { Describe("clean up on create", func() { JustBeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) _, err := Runner.Create(groot.CreateSpec{ ID: "my-image-1", BaseImage: baseImagePath, Mount: true, + Json: true, }) Expect(err).NotTo(HaveOccurred()) @@ -136,6 +146,7 @@ var _ = Describe("Create with local images", func() { ID: "my-image-2", BaseImage: baseImage2Path, Mount: true, + Json: true, } _, err := Runner.Create(createSpec) Expect(err).NotTo(HaveOccurred()) @@ -222,9 +233,11 @@ var _ = Describe("Create with local images", func() { image, err := Runner.Create(groot.CreateSpec{ ID: "random-id-2", BaseImage: baseImagePath, - Mount: true, + Mount: mountByDefault(), + Json: true, }) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) imageContentPath := path.Join(image.Rootfs, "foo") Expect(imageContentPath).To(BeARegularFile()) @@ -245,8 +258,10 @@ var _ = Describe("Create with local images", func() { image, err := Runner.Create(groot.CreateSpec{ ID: "random-id-2", BaseImage: baseImagePath, - Mount: true, + Mount: mountByDefault(), + Json: true, }) + Expect(Runner.EnsureMounted(image)).To(Succeed()) Expect(err).NotTo(HaveOccurred()) Expect(path.Join(image.Rootfs, "foo")).To(BeARegularFile()) Expect(path.Join(image.Rootfs, "injected-file")).To(BeARegularFile()) @@ -258,7 +273,8 @@ var _ = Describe("Create with local images", func() { _, err := Runner.Create(groot.CreateSpec{ BaseImage: "/invalid/image", ID: "random-id", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(MatchError(ContainSubstring("stat /invalid/image: no such file or directory"))) }) @@ -278,6 +294,7 @@ var _ = Describe("Create with local images", func() { It("unpacks the symlinks", func() { image, err := Runner.Create(spec) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) content, err := ioutil.ReadFile(filepath.Join(image.Rootfs, "symlink")) Expect(err).NotTo(HaveOccurred()) @@ -295,6 +312,7 @@ var _ = Describe("Create with local images", func() { It("preserves the timestamps", func() { image, err := Runner.Create(spec) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) symlinkTargetFilePath := path.Join(image.Rootfs, "symlink-target") symlinkTargetFi, err := os.Stat(symlinkTargetFilePath) diff --git a/integration/create_remote_test.go b/integration/create_remote_test.go index 0dbe4ba9c..4c49a71af 100644 --- a/integration/create_remote_test.go +++ b/integration/create_remote_test.go @@ -19,6 +19,7 @@ import ( "code.cloudfoundry.org/grootfs/commands/config" "code.cloudfoundry.org/grootfs/groot" + "code.cloudfoundry.org/grootfs/integration" "code.cloudfoundry.org/grootfs/store" "code.cloudfoundry.org/grootfs/testhelpers" "code.cloudfoundry.org/lager" @@ -32,6 +33,10 @@ import ( ) var _ = Describe("Create with remote images", func() { + BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) + }) + var baseImageURL string Context("when using the default registry", func() { diff --git a/integration/create_test.go b/integration/create_test.go index 18468508c..0328dc16f 100644 --- a/integration/create_test.go +++ b/integration/create_test.go @@ -82,10 +82,12 @@ var _ = Describe("Create", func() { image, err := Runner.Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "random-id", - Mount: true, + Mount: mountByDefault(), + Json: true, }) Expect(err).ToNot(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) grootFi, err := os.Stat(path.Join(image.Rootfs, "foo")) Expect(err).NotTo(HaveOccurred()) Expect(grootFi.Sys().(*syscall.Stat_t).Uid).To(Equal(uint32(GrootUID))) @@ -108,7 +110,8 @@ var _ = Describe("Create", func() { Create(groot.CreateSpec{ ID: "some-id", BaseImage: baseImagePath, - Mount: true, + Mount: mountByDefault(), + Json: true, UIDMappings: []groot.IDMappingSpec{ groot.IDMappingSpec{HostID: int(GrootUID), NamespaceID: 0, Size: 1}, groot.IDMappingSpec{HostID: 100000, NamespaceID: 1, Size: 65000}, @@ -118,13 +121,14 @@ var _ = Describe("Create", func() { groot.IDMappingSpec{HostID: 100000, NamespaceID: 1, Size: 65000}, }, }) - Expect(err).NotTo(HaveOccurred()) - grootFi, err := os.Stat(path.Join(image.Rootfs, "foo")) + Expect(Runner.EnsureMounted(image)).To(Succeed()) + + grootFile, err := os.Stat(path.Join(image.Rootfs, "foo")) Expect(err).NotTo(HaveOccurred()) - Expect(grootFi.Sys().(*syscall.Stat_t).Uid).To(Equal(uint32(GrootUID + 99999))) - Expect(grootFi.Sys().(*syscall.Stat_t).Gid).To(Equal(uint32(GrootGID + 99999))) + Expect(grootFile.Sys().(*syscall.Stat_t).Uid).To(Equal(uint32(GrootUID + 99999))) + Expect(grootFile.Sys().(*syscall.Stat_t).Gid).To(Equal(uint32(GrootGID + 99999))) grootDir, err := os.Stat(path.Join(image.Rootfs, "groot-folder")) Expect(err).NotTo(HaveOccurred()) @@ -150,7 +154,8 @@ var _ = Describe("Create", func() { It("allows the mapped user to have access to the created image", func() { image, err := Runner.WithLogLevel(lager.DEBUG). Create(groot.CreateSpec{ - Mount: true, + Mount: mountByDefault(), + Json: true, ID: "some-id", BaseImage: baseImagePath, UIDMappings: []groot.IDMappingSpec{ @@ -163,6 +168,7 @@ var _ = Describe("Create", func() { }, }) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) listRootfsCmd := exec.Command("ls", filepath.Join(image.Rootfs, "root-folder")) listRootfsCmd.SysProcAttr = &syscall.SysProcAttr{ @@ -180,12 +186,15 @@ var _ = Describe("Create", func() { Context("storage setup", func() { It("creates the storage path with the correct permission", func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) + storePath := filepath.Join(StorePath, "new-store") Expect(storePath).ToNot(BeAnExistingFile()) - _, err := Runner.WithStore(storePath).Create(groot.CreateSpec{ + _, err := Runner.WithStore(storePath).SkipInitStore().Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "random-id", - Mount: true, + Mount: false, + Json: true, }) Expect(err).ToNot(HaveOccurred()) Expect(storePath).To(BeADirectory()) @@ -200,7 +209,8 @@ var _ = Describe("Create", func() { Create(groot.CreateSpec{ ID: "some-id", BaseImage: baseImagePath, - Mount: true, + Mount: false, + Json: true, }) Expect(err).NotTo(HaveOccurred()) @@ -227,7 +237,8 @@ var _ = Describe("Create", func() { Create(groot.CreateSpec{ ID: "some-id", BaseImage: baseImagePath, - Mount: true, + Mount: false, + Json: true, UIDMappings: []groot.IDMappingSpec{ groot.IDMappingSpec{HostID: 1000, NamespaceID: 0, Size: 1}, groot.IDMappingSpec{HostID: 100000, NamespaceID: 1, Size: 65000}, @@ -262,7 +273,8 @@ var _ = Describe("Create", func() { Create(groot.CreateSpec{ ID: "some-id", BaseImage: baseImagePath, - Mount: true, + Mount: false, + Json: true, UIDMappings: []groot.IDMappingSpec{ groot.IDMappingSpec{HostID: 100000, NamespaceID: 1, Size: 65000}, }, @@ -280,11 +292,12 @@ var _ = Describe("Create", func() { Describe("create", func() { It("logs the image id", func() { logBuffer := gbytes.NewBuffer() - _, err := Runner.WithStore("/invalid/store/path").WithStderr(logBuffer). + _, err := Runner.WithStore("/an/invalid/path").SkipInitStore().WithStderr(logBuffer). Create(groot.CreateSpec{ ID: "random-id", BaseImage: "my-image", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(HaveOccurred()) Expect(logBuffer).To(gbytes.Say(`"id":"random-id"`)) @@ -295,6 +308,7 @@ var _ = Describe("Create", func() { Context("when disk limit is provided", func() { BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) Expect(writeMegabytes(filepath.Join(sourceImagePath, "fatfile"), 5)).To(Succeed()) }) @@ -354,7 +368,8 @@ var _ = Describe("Create", func() { image, err := Runner.Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "foobar", - Mount: true, + Mount: false, + Json: true, UIDMappings: []groot.IDMappingSpec{ groot.IDMappingSpec{HostID: int(GrootUID), NamespaceID: 0, Size: 1}, groot.IDMappingSpec{HostID: 100000, NamespaceID: 1, Size: 65000}, @@ -365,14 +380,15 @@ var _ = Describe("Create", func() { }, }) Expect(err).ToNot(HaveOccurred()) - Expect(image.Path).To(BeADirectory()) + Expect(image.Rootfs).To(BeADirectory()) }) It("returns a useful error message", func() { _, err := Runner.Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "foobar2", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(MatchError("store already initialized with a different mapping")) }) @@ -381,14 +397,13 @@ var _ = Describe("Create", func() { Context("when --with-clean is given", func() { BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) _, err := Runner.Create(groot.CreateSpec{ ID: "my-busybox", BaseImage: "docker:///busybox:1.26.2", Mount: true, - DiskLimit: 10 * 1024 * 1024, }) Expect(err).NotTo(HaveOccurred()) - Expect(Runner.Delete("my-busybox")).To(Succeed()) }) @@ -404,7 +419,8 @@ var _ = Describe("Create", func() { _, err = Runner.Create(groot.CreateSpec{ ID: "my-empty", BaseImage: "docker:///cfgarden/empty:v0.1.1", - Mount: true, + Mount: false, + Json: true, CleanOnCreate: true, }) Expect(err).NotTo(HaveOccurred()) @@ -420,6 +436,7 @@ var _ = Describe("Create", func() { Context("when --without-clean is given", func() { BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) _, err := Runner.Create(groot.CreateSpec{ ID: "my-busybox", BaseImage: "docker:///busybox:1.26.2", @@ -443,6 +460,7 @@ var _ = Describe("Create", func() { ID: "my-empty", BaseImage: "docker:///cfgarden/empty:v0.1.1", Mount: true, + Json: true, CleanOnCreate: false, }) Expect(err).NotTo(HaveOccurred()) @@ -463,7 +481,7 @@ var _ = Describe("Create", func() { _, err := Runner.WithClean().WithNoClean().Create(groot.CreateSpec{ ID: "my-empty", BaseImage: "docker:///cfgarden/empty:v0.1.1", - Mount: true, + Mount: false, }) Expect(err).To(MatchError(ContainSubstring("with-clean and without-clean cannot be used together"))) }) @@ -474,45 +492,29 @@ var _ = Describe("Create", func() { _, err := Runner.WithJson().WithNoJson().Create(groot.CreateSpec{ ID: "my-empty", BaseImage: "docker:///cfgarden/empty:v0.1.1", - Mount: true, + Mount: false, }) Expect(err).To(MatchError(ContainSubstring("json and no-json cannot be used together"))) }) }) - Context("when no --store option is given", func() { - BeforeEach(func() { - integration.SkipIfNotBTRFS(Driver) - integration.SkipIfNonRoot(GrootfsTestUid) - }) - - It("uses the default store path", func() { - Expect("/var/lib/grootfs/images").ToNot(BeAnExistingFile()) - _, err := Runner.WithoutStore().Create(groot.CreateSpec{ - BaseImage: baseImagePath, - ID: "random-id", - Mount: true, - }) - Expect(err).NotTo(HaveOccurred()) - Expect("/var/lib/grootfs/images").To(BeADirectory()) - }) - }) - Context("when the id is already being used", func() { JustBeforeEach(func() { _, err := Runner.Create(groot.CreateSpec{ ID: "random-id", BaseImage: baseImagePath, - Mount: true, + Mount: false, + Json: true, }) Expect(err).NotTo(HaveOccurred()) }) It("fails and produces a useful error", func() { - _, err := Runner.WithStore(StorePath).Create(groot.CreateSpec{ + _, err := Runner.Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "random-id", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(MatchError(ContainSubstring("image for id `random-id` already exists"))) }) @@ -523,7 +525,7 @@ var _ = Describe("Create", func() { _, err := Runner.WithStore(StorePath).Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "", - Mount: true, + Mount: false, }) Expect(err).To(HaveOccurred()) }) @@ -534,7 +536,8 @@ var _ = Describe("Create", func() { _, err := Runner.WithStore(StorePath).Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "this/is/not/okay", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(MatchError(ContainSubstring("id `this/is/not/okay` contains invalid characters: `/`"))) }) @@ -545,7 +548,8 @@ var _ = Describe("Create", func() { _, err := Runner.WithStore("/mnt/ext4").Create(groot.CreateSpec{ BaseImage: baseImagePath, ID: "random-id", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(MatchError("Image id 'random-id': Store path filesystem (/mnt/ext4) is incompatible with requested driver")) }) @@ -557,6 +561,7 @@ var _ = Describe("Create", func() { BaseImage: baseImagePath, ID: "some-id", Mount: true, + Json: true, }) Expect(err).To(MatchError(ContainSubstring("filesystem driver not supported: dinosaurfs"))) }) @@ -567,7 +572,8 @@ var _ = Describe("Create", func() { _, err := Runner.Create(groot.CreateSpec{ ID: "some-id", BaseImage: "*@#%^!&", - Mount: true, + Mount: false, + Json: true, }) Expect(err).To(MatchError(ContainSubstring("parsing image url: parse"))) Expect(err).To(MatchError(ContainSubstring("invalid URL escape"))) @@ -588,7 +594,8 @@ var _ = Describe("Create", func() { spec = groot.CreateSpec{ ID: "random-id", BaseImage: baseImagePath, - Mount: true, + Mount: mountByDefault(), + Json: true, } }) @@ -687,9 +694,15 @@ var _ = Describe("Create", func() { }) It("uses the uid mappings from the config file", func() { - image, err := Runner.Create(spec) + image, err := Runner.Create(groot.CreateSpec{ + ID: "random-id", + BaseImage: baseImagePath, + Mount: mountByDefault(), + Json: true, + }) Expect(err).NotTo(HaveOccurred()) + Expect(Runner.EnsureMounted(image)).To(Succeed()) rootOwnedFile, err := os.Stat(filepath.Join(image.Rootfs, "bar")) Expect(err).NotTo(HaveOccurred()) Expect(rootOwnedFile.Sys().(*syscall.Stat_t).Uid).To(Equal(uint32(1000))) @@ -721,6 +734,7 @@ var _ = Describe("Create", func() { Describe("disk limit size bytes", func() { BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) cfg.Create.DiskLimitSizeBytes = tenMegabytes }) @@ -738,12 +752,14 @@ var _ = Describe("Create", func() { ID: "random-id", BaseImage: baseImagePath, Json: true, - Mount: true, + Mount: false, }) Expect(err).ToNot(HaveOccurred()) - Expect(image.Rootfs).To(Equal(filepath.Join(StorePath, store.ImageDirName, "random-id/rootfs"))) - Expect(image.Mount).To(BeNil()) + expectedRootfs := filepath.Join(StorePath, store.ImageDirName, "random-id/rootfs") + Expect(image.Rootfs).To(Equal(expectedRootfs)) + Expect(image.Mount).NotTo(BeNil()) + Expect(image.Mount.Destination).To(Equal(expectedRootfs)) Expect(image.Config).To(BeNil()) }) }) @@ -773,8 +789,8 @@ var _ = Describe("Create", func() { image, err = Runner.Create(groot.CreateSpec{ ID: "some-id", BaseImage: baseImagePath, - Json: true, Mount: false, + Json: true, }) Expect(err).NotTo(HaveOccurred()) }) @@ -820,8 +836,8 @@ var _ = Describe("Create", func() { _, err := Runner.Create(groot.CreateSpec{ ID: "my-empty", BaseImage: "docker:///cfgarden/empty:v0.1.1", - Json: false, Mount: false, + Json: false, }) Expect(err).To(MatchError(ContainSubstring("without-mount option must be used with the json option"))) }) @@ -831,6 +847,7 @@ var _ = Describe("Create", func() { Describe("exclude image from quota", func() { BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) cfg.Create.ExcludeImageFromQuota = true cfg.Create.DiskLimitSizeBytes = tenMegabytes }) diff --git a/integration/delete_test.go b/integration/delete_test.go index 7203cd674..b03de7bb9 100644 --- a/integration/delete_test.go +++ b/integration/delete_test.go @@ -22,6 +22,7 @@ var _ = Describe("Delete", func() { BeforeEach(func() { var err error + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) sourceImagePath, err = ioutil.TempDir("", "") Expect(err).NotTo(HaveOccurred()) Expect(ioutil.WriteFile(path.Join(sourceImagePath, "foo"), []byte("hello-world"), 0644)).To(Succeed()) diff --git a/integration/list_test.go b/integration/list_test.go index 285378b22..70744305b 100644 --- a/integration/list_test.go +++ b/integration/list_test.go @@ -20,6 +20,7 @@ var _ = Describe("List", func() { var image groot.ImageInfo BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) sourceImagePath, err := ioutil.TempDir("", "") Expect(err).NotTo(HaveOccurred()) diff --git a/integration/metrics_test.go b/integration/metrics_test.go index 3b16750e7..07dd3db49 100644 --- a/integration/metrics_test.go +++ b/integration/metrics_test.go @@ -9,6 +9,7 @@ import ( "code.cloudfoundry.org/grootfs/commands/config" "code.cloudfoundry.org/grootfs/groot" + "code.cloudfoundry.org/grootfs/integration" "code.cloudfoundry.org/grootfs/testhelpers" "github.com/cloudfoundry/sonde-go/events" . "github.com/onsi/ginkgo" @@ -24,6 +25,7 @@ var _ = Describe("Metrics", func() { ) BeforeEach(func() { + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) fakeMetronPort = uint16(5000 + GinkgoParallelNode()) fakeMetron = testhelpers.NewFakeMetron(fakeMetronPort) diff --git a/integration/runner/create.go b/integration/runner/create.go index 04d99848d..1692b3f20 100644 --- a/integration/runner/create.go +++ b/integration/runner/create.go @@ -3,21 +3,42 @@ package runner import ( "encoding/json" "fmt" + "io/ioutil" + "os" "path/filepath" "strconv" + "syscall" + + yaml "gopkg.in/yaml.v2" + + errorspkg "github.com/pkg/errors" "github.com/onsi/gomega/gexec" + "code.cloudfoundry.org/grootfs/commands/config" "code.cloudfoundry.org/grootfs/groot" + "code.cloudfoundry.org/grootfs/store/filesystems/overlayxfs" ) func (r Runner) StartCreate(spec groot.CreateSpec) (*gexec.Session, error) { + if !r.skipInitStore { + if err := r.initStore(); err != nil { + return nil, err + } + } args := r.makeCreateArgs(spec) return r.StartSubcommand("create", args...) } -func (r Runner) Create(spec groot.CreateSpec, extraArgs ...string) (groot.ImageInfo, error) { - output, err := r.create(spec) +func (r Runner) Create(spec groot.CreateSpec) (groot.ImageInfo, error) { + if !r.skipInitStore { + if err := r.initStore(); err != nil { + return groot.ImageInfo{}, err + } + } + + args := r.makeCreateArgs(spec) + output, err := r.RunSubcommand("create", args...) if err != nil { return groot.ImageInfo{}, err } @@ -35,14 +56,12 @@ func (r Runner) Create(spec groot.CreateSpec, extraArgs ...string) (groot.ImageI return imageInfo, nil } -func (r Runner) create(spec groot.CreateSpec) (string, error) { - args := r.makeCreateArgs(spec) - image, err := r.RunSubcommand("create", args...) - if err != nil { - return "", err +func (r Runner) EnsureMounted(image groot.ImageInfo) error { + if image.Mount != nil { + return syscall.Mount(image.Mount.Source, image.Mount.Destination, image.Mount.Type, 0, image.Mount.Options[0]) } - return image, nil + return nil } func (r Runner) makeCreateArgs(spec groot.CreateSpec) []string { @@ -123,3 +142,48 @@ func (r Runner) makeCreateArgs(spec groot.CreateSpec) []string { return args } + +func (r Runner) initStore() error { + GrootfsTestUid, _ := strconv.Atoi(os.Getenv("GROOTFS_TEST_UID")) + GrootfsTestGid, _ := strconv.Atoi(os.Getenv("GROOTFS_TEST_GID")) + + storePath := r.StorePath + if r.StorePath == "" { + configBytes, err := ioutil.ReadFile(r.ConfigPath) + + if err != nil { + return err + } + cfg := config.Config{} + err = yaml.Unmarshal(configBytes, &cfg) + if err != nil { + return err + } + storePath = cfg.StorePath + } + + whiteoutDevicePath := filepath.Join(storePath, overlayxfs.WhiteoutDevice) + + if _, err := os.Stat(storePath); os.IsNotExist(err) { + os.MkdirAll(storePath, 0700) + } + + if err := os.Chown(storePath, GrootfsTestUid, GrootfsTestGid); err != nil { + return errorspkg.Wrapf(err, "changing store owner to %d:%d for path %s", GrootfsTestUid, GrootfsTestGid, storePath) + } + + if r.Driver == "overlay-xfs" { + if _, err := os.Stat(whiteoutDevicePath); os.IsNotExist(err) { + if err := syscall.Mknod(whiteoutDevicePath, syscall.S_IFCHR, 0); err != nil { + if err != nil && !os.IsExist(err) { + return errorspkg.Wrapf(err, "failed to create whiteout device %s", whiteoutDevicePath) + } + } + + if err := os.Chown(whiteoutDevicePath, GrootfsTestUid, GrootfsTestGid); err != nil { + return errorspkg.Wrapf(err, "changing store owner to %d:%d for path %s", GrootfsTestUid, GrootfsTestGid, whiteoutDevicePath) + } + } + } + return nil +} diff --git a/integration/runner/globals.go b/integration/runner/globals.go index fc7b283b9..79ee278fa 100644 --- a/integration/runner/globals.go +++ b/integration/runner/globals.go @@ -31,6 +31,12 @@ func (r Runner) WithInsecureRegistry(registry string) Runner { return nr } +func (r Runner) SkipInitStore() Runner { + nr := r + nr.skipInitStore = true + return nr +} + /////////////////////////////////////////////////////////////////////////////// // Store path /////////////////////////////////////////////////////////////////////////////// diff --git a/integration/runner/runner.go b/integration/runner/runner.go index dd21ee385..03d6769de 100644 --- a/integration/runner/runner.go +++ b/integration/runner/runner.go @@ -22,7 +22,8 @@ type Runner struct { Driver string // Store path - StorePath string + StorePath string + skipInitStore bool // Binaries DraxBin string TardisBin string diff --git a/integration/stats_test.go b/integration/stats_test.go index 7ff7b3dee..8d3066bde 100644 --- a/integration/stats_test.go +++ b/integration/stats_test.go @@ -28,6 +28,7 @@ var _ = Describe("Stats", func() { BeforeEach(func() { var err error + integration.SkipIfNonRootAndNotBTRFS(GrootfsTestUid, Driver) sourceImagePath, err = ioutil.TempDir("", "") Expect(err).NotTo(HaveOccurred()) imageID = fmt.Sprintf("random-id-%d", rand.Int()) diff --git a/integration/utils.go b/integration/utils.go index e4b8a6411..ff59ad8be 100644 --- a/integration/utils.go +++ b/integration/utils.go @@ -76,6 +76,12 @@ func SkipIfNonRoot(uid int) { } } +func SkipIfNonRootAndNotBTRFS(uid int, driver string) { + if uid != 0 && driver != "btrfs" { + Skip("These tests can only run as root user for xfs. Skipping.") + } +} + func CreateFakeDrax() (string, *os.File, *os.File) { tempFolder, bin, binCalledFile := CreateFakeBin("drax") testhelpers.SuidBinary(bin.Name())