func (b *LinuxBackend) ApplyLimits(container garden.Container, limits garden.Limits) error { if limits.CPU != (garden.CPULimits{}) { if err := container.LimitCPU(limits.CPU); err != nil { return err } } if limits.Disk != (garden.DiskLimits{}) { if err := container.LimitDisk(limits.Disk); err != nil { return err } } if limits.Bandwidth != (garden.BandwidthLimits{}) { if err := container.LimitBandwidth(limits.Bandwidth); err != nil { return err } } if limits.Memory != (garden.MemoryLimits{}) { if err := container.LimitMemory(limits.Memory); err != nil { return err } } return nil }
BeforeEach(func() { fakeConnection.LimitCPUReturns(garden.CPULimits{}, disaster) }) It("returns the error", func() { err := container.LimitCPU(garden.CPULimits{}) Ω(err).Should(Equal(disaster)) }) }) }) Describe("LimitDisk", func() { It("sends a limit bandwidth request", func() { err := container.LimitDisk(garden.DiskLimits{ ByteHard: 1, }) Ω(err).ShouldNot(HaveOccurred()) handle, limits := fakeConnection.LimitDiskArgsForCall(0) Ω(handle).Should(Equal("some-handle")) Ω(limits).Should(Equal(garden.DiskLimits{ByteHard: 1})) }) Context("when the request fails", func() { disaster := errors.New("oh no!") BeforeEach(func() { fakeConnection.LimitDiskReturns(garden.DiskLimits{}, disaster) })
Describe("LimitDisk", func() { Context("with quotas disabled", func() { BeforeEach(func() { startGardenArgs = []string{"-disableQuotas=true"} rootfs = runner.RootFSPath privilegedContainer = true }) Context("and there is a disk limit", func() { quotaLimit := garden.DiskLimits{ ByteSoft: 5 * 1024 * 1024, ByteHard: 5 * 1024 * 1024, } JustBeforeEach(func() { Expect(container.LimitDisk(quotaLimit)).To(Succeed()) }) It("reports the disk limit size of the container as zero", func() { limit, err := container.CurrentDiskLimits() Expect(err).ToNot(HaveOccurred()) Expect(limit).To(Equal(garden.DiskLimits{})) }) Context("and it runs a process that exceeds the limit", func() { It("does not kill the process", func() { dd, err := container.Run(garden.ProcessSpec{ User: "******", Path: "dd", Args: []string{"if=/dev/zero", "of=/tmp/some-file", "bs=1M", "count=6"}, }, garden.ProcessIO{})
close(done) }, 10.0) }) Describe("disk limits", func() { var container garden.Container AfterEach(func() { err := client.Destroy(container.Handle()) Expect(err).ShouldNot(HaveOccurred()) }) It("generated data is enforced", func() { container = createDefaultContainer() limitInBytes := uint64(15 * 1024 * 1024) err := container.LimitDisk(garden.DiskLimits{ByteHard: limitInBytes}) Expect(err).ShouldNot(HaveOccurred()) buf := make([]byte, 0, 1024*1024) stdout := bytes.NewBuffer(buf) process, err := container.Run(garden.ProcessSpec{ Path: "bin/consume.exe", Args: []string{"disk", "10"}, }, garden.ProcessIO{Stdout: stdout}) Expect(err).ShouldNot(HaveOccurred()) exitCode, err := process.Wait() Expect(err).ShouldNot(HaveOccurred()) Expect(stdout.String()).To(ContainSubstring("Consumed: 3 mb")) Expect(stdout.String()).NotTo(ContainSubstring("Consumed: 10 mb"))
BeforeEach(func() { setLimits = garden.DiskLimits{ BlockSoft: 111, BlockHard: 222, InodeSoft: 333, InodeHard: 444, ByteSoft: 555, ByteHard: 666, } }) It("sets the container's disk limits and returns the current limits", func() { err := container.LimitDisk(setLimits) Ω(err).ShouldNot(HaveOccurred()) Ω(fakeContainer.LimitDiskArgsForCall(0)).Should(Equal(setLimits)) }) itResetsGraceTimeWhenHandling(func() { err := container.LimitDisk(setLimits) Ω(err).ShouldNot(HaveOccurred()) }) itFailsWhenTheContainerIsNotFound(func() error { return container.LimitDisk(garden.DiskLimits{}) }) Context("when limiting the disk fails", func() {
ghttp.CombineHandlers( ghttp.VerifyRequest("POST", "/api/containers/containerhandle/disk_limit"), ghttp.RespondWith(200, `{}`), func(w http.ResponseWriter, req *http.Request) { body, err := ioutil.ReadAll(req.Body) req.Body.Close() Expect(err).ShouldNot(HaveOccurred()) requestBody = string(body) }, ), ) }) It("sets limits on the container", func() { limit := garden.DiskLimits{ByteHard: 555} err := container.LimitDisk(limit) Expect(err).NotTo(HaveOccurred()) Expect(server.ReceivedRequests()).Should(HaveLen(1)) Expect(requestBody).Should(Equal(`{"byte_hard":555}`)) }) }) Context("Containerizer returns non 200", func() { BeforeEach(func() { server.AppendHandlers( ghttp.CombineHandlers( ghttp.VerifyRequest("POST", "/api/containers/containerhandle/disk_limit"), ghttp.RespondWith(500, "{}"), ), )