func (g *Gardener) GraceTime(container garden.Container) time.Duration { property, ok := g.PropertyManager.Get(container.Handle(), GraceTimeKey) if !ok { return 0 } var graceTime time.Duration _, err := fmt.Sscanf(property, "%d", &graceTime) if err != nil { return 0 } return graceTime }
func createAndStream(index int, b Benchmarker, archive string) { var handle string var ctr garden.Container var err error b.Time(fmt.Sprintf("stream-%d", index), func() { creationTime := b.Time(fmt.Sprintf("create-%d", index), func() { By("creating container " + strconv.Itoa(index)) ctr, err = gardenClient.Create(garden.ContainerSpec{ Limits: garden.Limits{ Disk: garden.DiskLimits{ByteHard: 2 * 1024 * 1024 * 1024}, }, Privileged: true, }) Expect(err).ToNot(HaveOccurred()) handle = ctr.Handle() By("done creating container " + strconv.Itoa(index)) }) now := time.Now() emitMetric(map[string]interface{}{ "series": []map[string]interface{}{ { "metric": "garden.container-creation-time", "points": [][]int64{ {now.Unix(), int64(creationTime)}, }, "tags": []string{"deployment:" + os.Getenv("ENVIRONMENT") + "-garden"}, }, }, }) By("starting stream in to container " + handle) streamin(ctr, archive) By("succefully streamed in to container " + handle) b.Time(fmt.Sprintf("delete-%d", index), func() { By("destroying container " + handle) Expect(gardenClient.Destroy(handle)).To(Succeed()) By("successfully destroyed container " + handle) }) }) }
func streamin(ctr garden.Container, archive string) { for i := 0; i < 20; i++ { By(fmt.Sprintf("preparing stream %d for handle %s", i, ctr.Handle())) // Stream in a tar file to ctr var tarStream io.Reader pwd, err := os.Getwd() Expect(err).ToNot(HaveOccurred()) tgzPath := path.Join(pwd, archive) tgz, err := os.Open(tgzPath) Expect(err).ToNot(HaveOccurred()) tarStream, err = gzip.NewReader(tgz) Expect(err).ToNot(HaveOccurred()) By(fmt.Sprintf("starting stream %d for handle: %s", i, ctr.Handle())) Expect(ctr.StreamIn(garden.StreamInSpec{ User: "******", Path: fmt.Sprintf("/root/stream-file-%d", i), TarStream: tarStream, })).To(Succeed()) By(fmt.Sprintf("stream %d done for handle: %s", i, ctr.Handle())) tgz.Close() } }
BeforeEach(func() { container = nil args = []string{} }) JustBeforeEach(func() { if supplyDefaultRootfs { client = startGarden(args...) } else { client = startGardenWithoutDefaultRootfs(args...) } }) AfterEach(func() { if container != nil { Expect(client.Destroy(container.Handle())).To(Succeed()) } }) Context("without a default rootfs", func() { BeforeEach(func() { supplyDefaultRootfs = false }) It("fails if a rootfs is not supplied in container spec", func() { var err error container, err = client.Create(garden.ContainerSpec{RootFSPath: ""}) Expect(err).To(HaveOccurred()) Expect(err).To(MatchError(ContainSubstring("RootFSPath: is a required parameter, since no default rootfs was provided to the server."))) })
Expect(err).NotTo(HaveOccurred()) process, err := container.Run(garden.ProcessSpec{ Path: "sh", Args: []string{"-c", ` while true; do echo 'sleeping' sleep 1 done `}, }, garden.ProcessIO{}) Expect(err).NotTo(HaveOccurred()) processID = process.ID() hostProcessDir := filepath.Join(client.DepotDir, container.Handle(), "processes", processID) hostPidFilePath := filepath.Join(hostProcessDir, "pidfile") // Finds the pid on the host. pidBytes, err := ioutil.ReadFile(hostPidFilePath) Expect(err).NotTo(HaveOccurred()) Expect(client.Stop()).To(Succeed()) pid, err := strconv.Atoi(string(pidBytes)) Expect(err).NotTo(HaveOccurred()) hostProcess, err := os.FindProcess(pid) Expect(err).NotTo(HaveOccurred()) Expect(hostProcess.Kill()).To(Succeed())
Expect(string(out)).NotTo(MatchRegexp(fmt.Sprintf("%sinstance.*", interfacePrefix))) }) It("destroys the remaining containers' bridges", func() { out, err := exec.Command("ifconfig").CombinedOutput() Expect(err).NotTo(HaveOccurred()) pattern := fmt.Sprintf(".*w%d%s.*", GinkgoParallelNode(), subnetName) Expect(string(out)).NotTo(MatchRegexp(pattern)) }) It("kills the container processes", func() { processes, err := exec.Command("ps", "aux").CombinedOutput() Expect(err).NotTo(HaveOccurred()) Expect(string(processes)).NotTo(ContainSubstring(fmt.Sprintf("run runc /tmp/test-garden-%d/containers/%s", GinkgoParallelNode(), container.Handle()))) }) Context("when the garden server does not shut down gracefully", func() { BeforeEach(func() { gracefulShutdown = false }) It("destroys orphaned containers' iptables filter rules", func() { out, err := exec.Command("iptables", "-w", "-S", "-t", "filter").CombinedOutput() Expect(err).NotTo(HaveOccurred()) Expect(string(out)).NotTo(MatchRegexp(fmt.Sprintf("%sinstance.*", interfacePrefix))) }) It("destroys orphaned containers' iptables nat rules", func() { out, err := exec.Command("iptables", "-w", "-S", "-t", "nat").CombinedOutput()
}) JustBeforeEach(func() { var err error client := New(fakeConnection) fakeConnection.CreateReturns("some-handle", nil) container, err = client.Create(garden.ContainerSpec{}) Ω(err).ShouldNot(HaveOccurred()) }) Describe("Handle", func() { It("returns the container's handle", func() { Ω(container.Handle()).Should(Equal("some-handle")) }) }) Describe("Stop", func() { It("sends a stop request", func() { err := container.Stop(true) Ω(err).ShouldNot(HaveOccurred()) handle, kill := fakeConnection.StopArgsForCall(0) Ω(handle).Should(Equal("some-handle")) Ω(kill).Should(BeTrue()) }) Context("when stopping fails", func() { disaster := errors.New("oh no!")
info, err := container.Info() Expect(err).NotTo(HaveOccurred()) Expect(info.State).To(Equal("active")) }) It("can return the network information", func() { info, err := container.Info() Expect(err).NotTo(HaveOccurred()) Expect(info.ContainerIP).To(Equal("10.252.0.2")) Expect(info.HostIP).To(Equal("10.252.0.1")) }) It("can return the container path", func() { info, err := container.Info() Expect(err).NotTo(HaveOccurred()) Expect(info.ContainerPath).To(Equal(path.Join(client.DepotDir, container.Handle()))) }) It("can return the list of properties", func() { Expect(container.SetProperty("abc", "xyz")).To(Succeed()) info, err := container.Info() Expect(err).NotTo(HaveOccurred()) Expect(info.Properties).To(HaveKeyWithValue("foo", "bar")) Expect(info.Properties).To(HaveKeyWithValue("abc", "xyz")) }) It("can return port mappings", func() { hostPort, containerPort, err := container.NetIn(0, 0) Expect(err).NotTo(HaveOccurred())
var itRemovesTheNetworkBridge = func() { It("should remove the network bridge", func() { session, err := gexec.Start( exec.Command("ip", "link", "show", networkBridgeName), GinkgoWriter, GinkgoWriter, ) Expect(err).NotTo(HaveOccurred()) session.Wait() Expect(session.ExitCode()).NotTo(Equal(0)) }) } Context("when destroy is called", func() { JustBeforeEach(func() { Expect(client.Destroy(container.Handle())).To(Succeed()) }) itCleansUpPerContainerNetworkingResources() itRemovesTheNetworkBridge() Context("and there was more than one containers in the same subnet", func() { var otherContainer garden.Container JustBeforeEach(func() { var err error otherContainer, err = client.Create(garden.ContainerSpec{ Network: networkSpec, }) Expect(err).NotTo(HaveOccurred())
Context("after creating a container without a specified handle", func() { var ( privileged bool initProcPid int ) JustBeforeEach(func() { var err error container, err = client.Create(garden.ContainerSpec{ Privileged: privileged, }) Expect(err).NotTo(HaveOccurred()) initProcPid = initProcessPID(container.Handle()) }) It("should create a depot subdirectory based on the container handle", func() { Expect(container.Handle()).NotTo(BeEmpty()) Expect(filepath.Join(client.DepotDir, container.Handle())).To(BeADirectory()) Expect(filepath.Join(client.DepotDir, container.Handle(), "config.json")).To(BeARegularFile()) }) It("should lookup the right container", func() { lookupContainer, lookupError := client.Lookup(container.Handle()) Expect(lookupError).NotTo(HaveOccurred()) Expect(lookupContainer).To(Equal(container)) })
Context("when destroying other containers on the same subnet", func() { It("should continue to route traffic successfully", func() { var ( err error googleDNSIP string otherContainer garden.Container ) googleDNSIP = "8.8.8.8" for i := 0; i < 5; i++ { otherContainer, err = gardenClient.Create(garden.ContainerSpec{ Network: networkSpec, }) Expect(err).NotTo(HaveOccurred()) Expect(gardenClient.Destroy(otherContainer.Handle())).To(Succeed()) Expect(checkConnection(container, googleDNSIP, 53)).To(Succeed()) } }) }) Context("when creating a container in a previously used subnet", func() { var newContainer garden.Container JustBeforeEach(func() { var err error Expect(gardenClient.Destroy(container.Handle())).To(Succeed()) newContainer, err = gardenClient.Create(garden.ContainerSpec{ Network: networkSpec,
SrcPath: srcPath, DstPath: dstPath, Mode: bindMountMode, Origin: bindMountOrigin, }}, Network: fmt.Sprintf("10.0.%d.0/24", GinkgoParallelNode()), }) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { err := os.RemoveAll(srcPath) Expect(err).ToNot(HaveOccurred()) if container != nil { err := client.Destroy(container.Handle()) Expect(err).ToNot(HaveOccurred()) } Expect(client.DestroyAndStop()).To(Succeed()) }) Context("which is read-only", func() { BeforeEach(func() { bindMountMode = garden.BindMountModeRO dstPath = "/home/alice/readonly" }) Context("and with privileged=true", func() { BeforeEach(func() { privilegedContainer = true
func (s *GardenServer) reapContainer(container garden.Container) { s.logger.Info("reaping", lager.Data{ "handle": container.Handle(), "grace-time": s.backend.GraceTime(container).String(), }) s.destroysL.Lock() _, alreadyDestroying := s.destroys[container.Handle()] if !alreadyDestroying { s.destroys[container.Handle()] = struct{}{} } s.destroysL.Unlock() if alreadyDestroying { s.logger.Info("skipping reap due to concurrent delete request", lager.Data{ "handle": container.Handle(), "grace-time": s.backend.GraceTime(container).String(), }) return } s.backend.Destroy(container.Handle()) s.destroysL.Lock() delete(s.destroys, container.Handle()) s.destroysL.Unlock() }
}) }) }) Describe("multiple containers", func() { var extraContainer garden.Container BeforeEach(func() { var err error extraContainer, err = gardenClient.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { if extraContainer != nil { Expect(gardenClient.Destroy(extraContainer.Handle())).To(Succeed()) } }) It("should list all containers", func() { containers, err := gardenClient.Containers(garden.Properties{}) Expect(err).ToNot(HaveOccurred()) handles := []string{} for _, c := range containers { handles = append(handles, c.Handle()) } Expect(handles).To(ContainElement(container.Handle())) Expect(handles).To(ContainElement(extraContainer.Handle())) })
}) Describe("a second container", func() { var otherContainer garden.Container JustBeforeEach(func() { var err error otherContainer, err = client.Create(garden.ContainerSpec{ Network: containerNetwork, }) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { Expect(client.Destroy(otherContainer.Handle())).To(Succeed()) }) It("should have the next IP address", func() { buffer := gbytes.NewBuffer() proc, err := otherContainer.Run( garden.ProcessSpec{ Path: "ifconfig", User: "******", }, garden.ProcessIO{Stdout: buffer}, ) Expect(err).NotTo(HaveOccurred()) Expect(proc.Wait()).To(Equal(0)) Expect(buffer).To(gbytes.Say(ipAddress(containerNetwork, 3)))