} var err error defaultBaseImage, err = url.Parse("/default/image") Expect(err).ToNot(HaveOccurred()) externalImageManager = imageplugin.New("/external-image-manager-bin", fakeCommandRunner, defaultBaseImage, idMappings) baseImage, err = url.Parse("/hello/image") Expect(err).ToNot(HaveOccurred()) fakeCommandRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "/external-image-manager-bin", }, func(cmd *exec.Cmd) error { if cmd.Stdout != nil { cmd.Stdout.Write([]byte(fakeCmdRunnerStdout)) } if cmd.Stderr != nil { cmd.Stderr.Write([]byte(fakeCmdRunnerStderr)) } return fakeCmdRunnerErr }) }) Describe("Create", func() { BeforeEach(func() { fakeCmdRunnerStdout = "/this-is/your\n" }) It("uses the correct external-image-manager binary", func() { _, _, err := externalImageManager.Create( logger, "hello", rootfs_provider.Spec{
{ Path: "/sbin/iptables", Args: []string{"--wait", "-A", "prefix-instance-some-id-log", "--jump", "RETURN"}, }, } }) It("should set up the chain", func() { Expect(creator.Create(logger, handle, "some-id", bridgeName, ip, network)).To(Succeed()) Expect(fakeRunner).To(HaveExecutedSerially(specs...)) }) DescribeTable("iptables failures", func(specIndex int, errorString string) { fakeRunner.WhenRunning(specs[specIndex], func(cmd *exec.Cmd) error { cmd.Stderr.Write([]byte("iptables failed")) return errors.New("Exit status blah") }) Expect(creator.Create(logger, handle, "some-id", bridgeName, ip, network)).To(MatchError(errorString)) }, Entry("create nat instance chain", 0, "iptables: create-instance-chains: iptables failed"), Entry("bind nat instance chain to nat prerouting chain", 1, "iptables: create-instance-chains: iptables failed"), Entry("enable NAT for traffic coming from containers", 2, "iptables: create-instance-chains: iptables failed"), Entry("create logging instance chain", 7, "iptables: create-instance-chains: iptables failed"), Entry("append logging to instance chain", 8, "iptables: create-instance-chains: iptables failed"), Entry("return from logging instance chain", 9, "iptables: create-instance-chains: iptables failed"), ) }) Describe("ContainerTeardown", func() { var specs []fake_command_runner.CommandSpec
}) Context("Inside the host", func() { Context("before container creation", func() { It("runs the hook-parent-before-clone.sh legacy shell script", func() { hooks.Main(hook.PARENT_BEFORE_CLONE) Expect(fakeRunner).To(HaveExecutedSerially(fake_command_runner.CommandSpec{ Path: "hook-parent-before-clone.sh", })) }) Context("when the legacy shell script fails", func() { BeforeEach(func() { fakeRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "hook-parent-before-clone.sh", }, func(*exec.Cmd) error { return errors.New("o no") }) }) It("panics", func() { Expect(func() { hooks.Main(hook.PARENT_BEFORE_CLONE) }).To(Panic()) }) }) }) Context("after container creation", func() { var oldWd, testDir string BeforeEach(func() { os.Setenv("PID", "99")
"some-user", "some-path", }, })) }) It("attaches the tarStream reader to stdin", func() { Expect(fakeCommandRunner.ExecutedCommands()[0].Stdin).To(Equal(someStream)) }) }) Context("when it fails", func() { It("returns the contents of stdout and error on failure", func() { fakeCommandRunner.WhenRunning(fake_command_runner.CommandSpec{}, func(cmd *exec.Cmd) error { cmd.Stderr.Write([]byte("some error output")) cmd.Stdout.Write([]byte("some std output")) return errors.New("someerror") }) Expect(nstar.StreamIn(lagertest.NewTestLogger("test"), 12, "some-path", "some-user", someStream)).To( MatchError(ContainSubstring("some error output")), ) Expect(nstar.StreamIn(lagertest.NewTestLogger("test"), 12, "some-path", "some-user", someStream)).To( MatchError(ContainSubstring("some std output")), ) }) }) Context("when no user specified", func() { It("streams the input to tar as root", func() {
Expect(container.State()).To(Equal(linux_backend.StateBorn)) err := container.Start() Expect(err).ToNot(HaveOccurred()) Expect(container.State()).To(Equal(linux_backend.StateActive)) }) Context("when start.sh fails", func() { nastyError := errors.New("oh no!") JustBeforeEach(func() { fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: containerDir + "/start.sh", }, func(*exec.Cmd) error { return nastyError }, ) }) It("returns a wrapped error", func() { err := container.Start() Expect(err).To(MatchError("container: start: oh no!")) }) It("does not change the container's state", func() { Expect(container.State()).To(Equal(linux_backend.StateBorn)) err := container.Start() Expect(err).To(HaveOccurred())
commandRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "funC-stats", }, func(cmd *exec.Cmd) error { cmd.Stdout.Write([]byte(`{ "type": "stats", "data": { "cpu": { "usage": { "total": 1, "kernel": 2, "user": 3 } }, "memory": { "raw": { "active_anon": 1, "active_file": 2, "cache": 3, "hierarchical_memory_limit": 4, "inactive_anon": 5, "inactive_file": 6, "mapped_file": 7, "pgfault": 8, "pgmajfault": 9, "pgpgin": 10, "pgpgout": 11, "rss": 12, "rss_huge": 13, "total_active_anon": 14, "total_active_file": 15, "total_cache": 16, "total_inactive_anon": 17, "total_inactive_file": 18, "total_mapped_file": 19, "total_pgfault": 20, "total_pgmajfault": 21, "total_pgpgin": 22, "total_pgpgout": 23, "total_rss": 24, "total_rss_huge": 25, "total_unevictable": 26, "total_writeback": 27, "unevictable": 28, "writeback": 29, "swap": 30, "hierarchical_memsw_limit": 31, "total_swap": 32 } } } }`)) return nil })
BeforeEach(func() { runcBinary = new(fakes.FakeRuncBinary) commandRunner = fake_command_runner.New() logger = lagertest.NewTestLogger("test") runner = runrunc.NewOomWatcher(commandRunner, runcBinary) runcBinary.EventsCommandStub = func(handle string) *exec.Cmd { return exec.Command("funC-events", "events", handle) } }) It("blows up if `runc events` returns an error", func() { commandRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "funC-events", }, func(cmd *exec.Cmd) error { return errors.New("boom") }) Expect(runner.WatchEvents(logger, "some-container", nil)).To(MatchError("start: boom")) }) Context("when runc events succeeds", func() { var ( eventsCh chan string eventsNotifier *fakes.FakeEventsNotifier ) BeforeEach(func() { eventsCh = make(chan string, 2)
It("runs a shell command", func() { step := &containerizer.ShellRunnerStep{Runner: runner, Path: path} err := step.Run() Expect(err).ToNot(HaveOccurred()) Expect(runner).To(HaveStartedExecuting( fake_command_runner.CommandSpec{ Path: "sh", Args: []string{path}, }, )) }) It("returns error if fails to start a shell command", func() { runner.WhenRunning(fake_command_runner.CommandSpec{}, func(*exec.Cmd) error { return errors.New("what") }) step := &containerizer.ShellRunnerStep{Runner: runner, Path: path} err := step.Run() Expect(err).To(HaveOccurred()) }) It("returns error if shell command does not exit 0", func() { runner.WhenWaitingFor(fake_command_runner.CommandSpec{}, func(*exec.Cmd) error { return errors.New("booo") }) step := &containerizer.ShellRunnerStep{Runner: runner, Path: path} err := step.Run() Expect(err).To(HaveOccurred())
It("creates a namespace using 'ip netns add'", func() { Expect(mgr.Create(logger, "my-namespace")).To(Succeed()) Expect(fakeRunner).To(HaveExecutedSerially(fake_command_runner.CommandSpec{ Path: "ip", Args: []string{ "netns", "add", "my-namespace", }, })) }) Context("when the command fails", func() { It("returns an error", func() { fakeRunner.WhenRunning( fake_command_runner.CommandSpec{}, func(*exec.Cmd) error { return errors.New("banana") }, ) Expect(mgr.Create(logger, "my-namespace")).NotTo(Succeed()) }) }) }) Describe("Looking up a Network Namespace path", func() { It("looks up the Network Namespace path", func() { Expect(ioutil.WriteFile(path.Join(netnsDir, "banana"), []byte(""), 0700)).To(Succeed()) path, theUnexpected := mgr.Lookup(logger, "banana") Expect(theUnexpected).NotTo(HaveOccurred()) Expect(path).To(Equal(filepath.Join(netnsDir, "banana")))
fakeCake = new(fake_cake.FakeCake) cleaner = &layercake.BtrfsCleaningCake{ Cake: fakeCake, Runner: runner, BtrfsMountPoint: btrfsMountPoint, RemoveAll: func(dir string) error { removedDirectories = append(removedDirectories, dir) return nil }, Logger: lagertest.NewTestLogger("test"), } runner.WhenRunning(fake_command_runner.CommandSpec{ Path: "btrfs", Args: []string{"subvolume", "list", btrfsMountPoint}, }, func(cmd *exec.Cmd) error { _, err := cmd.Stdout.Write([]byte(listSubvolumesOutput)) Expect(err).NotTo(HaveOccurred()) return listSubVolumeErr }) fakeCake.PathStub = func(id layercake.ID) (string, error) { return "/absolute/btrfs_mount/relative/path/to/" + id.GraphID(), graphDriverErr } }) Context("when there are no subvolumes", func() { BeforeEach(func() { listSubvolumesOutput = "\n" }) It("does not invoke subvolume delete", func() {
Args: []string{"-w", "-A", "foo-bar-baz-log", "-m", "conntrack", "--ctstate", "NEW,UNTRACKED,INVALID", "--protocol", "tcp", "--jump", "LOG", "--log-prefix", "logPrefix"}, }, fake_command_runner.CommandSpec{ Path: "/sbin/iptables", Args: []string{"-w", "-A", "foo-bar-baz-log", "--jump", "RETURN"}, })) }) }) It("ignores failures to flush", func() { someError := errors.New("y") fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: "/sbin/iptables", Args: []string{"-w", "-F", "foo-bar-baz-log"}, }, func(cmd *exec.Cmd) error { return someError }) Expect(subject.Setup("logPrefix")).To(Succeed()) }) It("ignores failures to delete", func() { someError := errors.New("y") fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: "/sbin/iptables", Args: []string{"-w", "-X", "foo-bar-baz-log"}, }, func(cmd *exec.Cmd) error {
Expect(bridgeName).To(Equal("some-bridge")) Expect(ip.String()).To(Equal("1.2.3.4")) Expect(network.String()).To(Equal("2.3.4.0/30")) }) for _, cmd := range []string{"in"} { command := cmd Context("when net.sh "+cmd+" fails", func() { disaster := errors.New("oh no!") JustBeforeEach(func() { fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: containerDir + "/net.sh", Args: []string{command}, }, func(*exec.Cmd) error { return disaster }, ) }) It("returns the error", func() { err := container.Restore(linux_backend.LinuxContainerSpec{ State: "active", Events: []string{}, Resources: containerResources, NetIns: []linux_backend.NetInSpec{ { HostPort: 1234, ContainerPort: 5678,
Expect(aufsCake.Create(namespacedChildID, parentID, "")).To(Equal(testError)) }) It("should not unmount the parent", func() { Expect(aufsCake.Create(namespacedChildID, parentID, "")).To(Equal(testError)) Expect(cake.UnmountCallCount()).To(Equal(0)) }) }) Context("when getting parent's path succeeds", func() { var succeedingRunner *fake_command_runner.FakeCommandRunner BeforeEach(func() { succeedingRunner = fake_command_runner.New() succeedingRunner.WhenRunning(fake_command_runner.CommandSpec{}, func(cmd *exec.Cmd) error { return nil }) }) It("should unmount the parentID", func() { aufsCake.Runner = succeedingRunner Expect(aufsCake.Create(namespacedChildID, parentID, "")).To(Succeed()) Expect(cake.UnmountCallCount()).To(Equal(1)) Expect(cake.UnmountArgsForCall(0)).To(Equal(parentID)) }) It("should only unmount the parentID after mounting it", func() { cake.UnmountStub = func(id layercake.ID) error { Expect(cake.PathCallCount()).Should(BeNumerically(">", 0)) Expect(cake.PathArgsForCall(0)).To(Equal(parentID)) return nil
})) } itAppendsRule := func(chain string, args ...string) { Expect(fakeRunner).To(HaveExecutedSerially(fake_command_runner.CommandSpec{ Path: "/sbin/iptables", Args: append([]string{"-w", "-A", chain}, args...), })) } Describe("Global chains setup", func() { Context("when the input chain does not exist", func() { BeforeEach(func() { fakeRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "/sbin/iptables", Args: []string{"-w", "-L", "prefix-input"}, }, func(_ *exec.Cmd) error { return errors.New("exit status 1") }) }) It("runs the setup script, passing the environment variables", func() { Expect(starter.Start()).To(Succeed()) itSetsUpGlobalChains() }) Context("when running the setup script fails", func() { BeforeEach(func() { fakeRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "bash", Args: []string{"-c", iptables.SetupScript},
Env: []string{ "BURST=256", fmt.Sprintf("RATE=%d", 128*8), }, }, )) }) Context("when net_rate.sh fails", func() { nastyError := errors.New("oh no!") BeforeEach(func() { fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: "/depot/some-id/net_rate.sh", }, func(*exec.Cmd) error { return nastyError }, ) }) It("returns the error", func() { err := bandwidthManager.SetLimits(warden.BandwidthLimits{ RateInBytesPerSecond: 128, BurstRateInBytesPerSecond: 256, }) Expect(err).To(Equal(nastyError)) }) }) })
fakeRunner = fake_command_runner.New() logger = lagertest.NewTestLogger("test") quotaManager = "a_manager.BtrfsQuotaManager{ Runner: fakeRunner, MountPoint: "/the/mount/point", } subvolumePath = "/some/volume/path" }) JustBeforeEach(func() { fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: "sh", Args: []string{"-c", fmt.Sprintf("btrfs qgroup show -rF --raw %s", subvolumePath)}, }, func(cmd *exec.Cmd) error { cmd.Stdout.Write(qgroupShowResponse) return qgroupShowError }, ) }) Describe("Setup", func() { It("enables quotas", func() { Expect(quotaManager.Setup()).To(Succeed()) Expect(fakeRunner).To(HaveExecutedSerially(fake_command_runner.CommandSpec{ Path: "btrfs", Args: []string{"quota", "enable", "/the/mount/point"}, })) }) })
network.String(), network.String(), )}, }, } }) It("should set up the chain", func() { Expect(chain.Setup(containerID, bridgeName, ip, network)).To(Succeed()) Expect(fakeRunner).To(HaveExecutedSerially(specs...)) }) DescribeTable("iptables failures", func(specIndex int, errorString string) { fakeRunner.WhenRunning(specs[specIndex], func(*exec.Cmd) error { return errors.New("iptables failed") }) Expect(chain.Setup(containerID, bridgeName, ip, network)).To(MatchError(errorString)) }, Entry("create nat instance chain", 0, "iptables_manager: nat: iptables failed"), Entry("bind nat instance chain to nat prerouting chain", 1, "iptables_manager: nat: iptables failed"), Entry("enable NAT for traffic coming from containers", 2, "iptables_manager: nat: iptables failed"), ) }) Describe("ContainerTeardown", func() { var specs []fake_command_runner.CommandSpec Describe("nat chain", func() { BeforeEach(func() {
"DISK_QUOTA_ENABLED=true", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", }, }, )) }) Context("when setup.sh fails", func() { nastyError := errors.New("oh no!") BeforeEach(func() { fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: "/root/path/setup.sh", }, func(*exec.Cmd) error { return nastyError }, ) }) It("returns the error", func() { err := pool.Setup() Expect(err).To(Equal(nastyError)) }) }) }) Describe("creating", func() { It("returns containers with unique IDs", func() { container1, err := pool.Create(warden.ContainerSpec{})
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Execer", func() { var execer *system.NamespacingExecer var commandRunner *fake_command_runner.FakeCommandRunner BeforeEach(func() { commandRunner = fake_command_runner.New() process := &os.Process{ Pid: 12, } commandRunner.WhenRunning(fake_command_runner.CommandSpec{}, func(cmd *exec.Cmd) error { cmd.Process = process return nil }) execer = &system.NamespacingExecer{ CommandRunner: commandRunner, } }) Describe("Exec", func() { It("executes the given command", func() { _, err := execer.Exec("something", "smthg") Expect(err).To(Succeed()) Expect(commandRunner).To(HaveStartedExecuting( fake_command_runner.CommandSpec{ Path: "something",
var err error bundlePath, err = ioutil.TempDir("", "bundle") Expect(err).NotTo(HaveOccurred()) logFilePath = filepath.Join(bundlePath, "create.log") pidFilePath = filepath.Join(bundlePath, "pidfile") runner = runrunc.NewCreator("funC", commandRunner) }) JustBeforeEach(func() { commandRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "funC", }, func(cmd *exec.Cmd) error { logFile, err := os.Create(cmd.Args[3]) Expect(err).NotTo(HaveOccurred()) _, err = io.Copy(logFile, bytes.NewReader([]byte(logs))) Expect(err).NotTo(HaveOccurred()) return runcExitStatus }) }) It("creates the container with runC create", func() { Expect(runner.Create(logger, bundlePath, "some-id", garden.ProcessIO{})).To(Succeed()) Expect(commandRunner.ExecutedCommands()[0].Path).To(Equal("funC")) Expect(commandRunner.ExecutedCommands()[0].Args).To(ConsistOf( "funC", "--debug", "--log", logFilePath, "create", "--no-new-keyring", "--bundle", bundlePath, "--pid-file", pidFilePath, "some-id", )) })
}) It("execs the command", func() { Expect(logRunner.RunAndLog(logger, func(logFile string) *exec.Cmd { return exec.Command("something.exe") })).To(Succeed()) Expect(commandRunner).To(HaveExecutedSerially(fake_command_runner.CommandSpec{ Path: "something.exe", })) }) It("forwards any logs coming from the log file", func() { commandRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "something.exe", }, func(cmd *exec.Cmd) error { ioutil.WriteFile(cmd.Args[1], []byte(logs), 0777) return nil }) logRunner.RunAndLog(logger, func(logFile string) *exec.Cmd { return exec.Command("something.exe", logFile) }) runcLogs := make([]lager.LogFormat, 0) for _, log := range logger.Logs() { if log.Message == "test.run.runc" { runcLogs = append(runcLogs, log) } } Expect(runcLogs).To(HaveLen(3))
fakeRunner.WhenRunning( fake_command_runner.CommandSpec{ Path: binPath("iomux-spawn"), }, func(cmd *exec.Cmd) error { go func() { defer GinkgoRecover() time.Sleep(100 * time.Millisecond) Expect(fakeRunner).ToNot(HaveStartedExecuting( fake_command_runner.CommandSpec{ Path: binPath("iomux-link"), }, ), "Executed iomux-link too early!") Expect(cmd.Stdout).ToNot(BeNil()) fakeRunner.WhenWaitingFor( fake_command_runner.CommandSpec{ Path: binPath("iomux-link"), }, func(*exec.Cmd) error { close(done) return nil }, ) cmd.Stdout.Write([]byte("xxx\n")) Eventually(fakeRunner).Should(HaveStartedExecuting( fake_command_runner.CommandSpec{ Path: binPath("iomux-link"), }, )) }() return nil }, )
) var _ = Describe("Linux Quota Manager initialization", func() { var fakeRunner *fake_command_runner.FakeCommandRunner BeforeEach(func() { fakeRunner = fake_command_runner.New() }) Context("when df fails", func() { disaster := errors.New("oh no!") BeforeEach(func() { fakeRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "df", }, func(*exec.Cmd) error { return disaster }) }) It("returns the error", func() { _, err := quota_manager.New("/bogus/path", "/root/path", fakeRunner) Expect(err).To(Equal(disaster)) }) }) }) var _ = Describe("Linux Quota manager", func() { var fakeRunner *fake_command_runner.FakeCommandRunner var quotaManager *quota_manager.LinuxQuotaManager
runner = fake_command_runner.New() }) It("returns true when it can successfully push an app", func() { tester := NewAppSizeBinarySearchTester(runner, appPath) Expect(tester.Test(100)).To(BeTrue()) }) It("returns false when it can't push an app", func() { pushCommand := fake_command_runner.CommandSpec{Path: "gcf"} runner.WhenRunning(pushCommand, func(cmd *exec.Cmd) error { return errors.New("PUSH FAILED") }) tester := NewAppSizeBinarySearchTester(runner, appPath) Expect(tester.Test(100)).To(BeFalse()) }) It("cleans up the app when it's done", func() { tester := NewAppSizeBinarySearchTester(runner, appPath) gcfCommand := fake_command_runner.CommandSpec{Path: "gcf"} ranGcfDelete := false runner.WhenRunning(gcfCommand, func(cmd *exec.Cmd) error {
}) AfterEach(func() { os.RemoveAll(tmpDir) }) It("mkdirs the cgroup path", func() { starter.Start() Expect(path.Join(tmpDir, "cgroup")).To(BeADirectory()) }) Context("when the cgroup path is not a mountpoint", func() { BeforeEach(func() { runner.WhenRunning(fake_command_runner.CommandSpec{ Path: "mountpoint", Args: []string{"-q", path.Join(tmpDir, "cgroup")}, }, func(cmd *exec.Cmd) error { return errors.New("not a mountpoint") }) }) It("mounts it", func() { starter.Start() Expect(runner).To(HaveExecutedSerially(fake_command_runner.CommandSpec{ Path: "mount", Args: []string{"-t", "tmpfs", "-o", "uid=0,gid=0,mode=0755", "cgroup", path.Join(tmpDir, "cgroup")}, })) }) }) Context("when the cgroup path exists", func() { It("does not mount it again", func() {
stateCmdExit = nil stateCmdOutput = `{ "Pid": 4, "Status": "quite-a-status" }` }) JustBeforeEach(func() { runner.RunAndLogStub = func(_ lager.Logger, fn runrunc.LoggingCmd) error { return commandRunner.Run(fn("potato.log")) } commandRunner.WhenRunning(fake_command_runner.CommandSpec{ Path: "funC-state", }, func(cmd *exec.Cmd) error { cmd.Stdout.Write([]byte(stateCmdOutput)) return stateCmdExit }) }) It("gets the bundle state", func() { state, err := stater.State(logger, "some-container") Expect(err).NotTo(HaveOccurred()) Expect(state.Pid).To(Equal(4)) Expect(state.Status).To(BeEquivalentTo("quite-a-status")) }) It("forwards runc logs", func() { _, err := stater.State(logger, "some-container") Expect(err).NotTo(HaveOccurred())