func (s *GardenServer) reapContainer(container garden.Container) { s.logger.Info("reaping", lager.Data{ "handle": container.Handle(), "grace-time": s.backend.GraceTime(container).String(), }) s.backend.Destroy(container.Handle()) }
func (exchanger exchanger) Info(logger lager.Logger, gardenContainer garden.Container) (executor.Container, error) { logger = logger.Session("info", lager.Data{"handle": gardenContainer.Handle()}) logger.Debug("getting-info") info, err := gardenContainer.Info() if err != nil { logger.Error("failed-getting-info", err) return executor.Container{}, err } logger.Debug("succeeded-getting-info") return garden2executor(gardenContainer.Handle(), info) }
}, ","), "-allowNetworks", allowedListenerIP+"/32", ) // check that the IPs were preserved over restart Expect(containerIP(blockedListener)).To(Equal(blockedListenerIP)) Expect(containerIP(unblockedListener)).To(Equal(unblockedListenerIP)) Expect(containerIP(allowedListener)).To(Equal(allowedListenerIP)) // create a container with the new deny network configuration sender, err = client.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { err := client.Destroy(sender.Handle()) Expect(err).ToNot(HaveOccurred()) err = client.Destroy(blockedListener.Handle()) Expect(err).ToNot(HaveOccurred()) err = client.Destroy(unblockedListener.Handle()) Expect(err).ToNot(HaveOccurred()) err = client.Destroy(allowedListener.Handle()) Expect(err).ToNot(HaveOccurred()) }) runInContainer := func(container garden.Container, script string) garden.Process { process, err := container.Run(garden.ProcessSpec{ User: "******",
} process, err := os.FindProcess(pingProcess.Pid()) if err == nil { process.Kill() } }) It("is not allowed", func() { // TODO: make the executable name unique so to avoid test pollution _, err := container.Run(garden.ProcessSpec{ Path: "bin/JobBreakoutTest.exe", Args: []string{"ping 192.0.2.2 -n 1 -w 10000"}, }, garden.ProcessIO{}) Expect(err).ShouldNot(HaveOccurred()) err = client.Destroy(container.Handle()) Expect(err).ShouldNot(HaveOccurred()) processes, err := ps.Processes() Expect(err).ShouldNot(HaveOccurred()) for _, proc := range processes { fmt.Println(proc.Executable()) if proc.Executable() == "PING.EXE" { pingProcess = proc Expect(proc.Executable()).NotTo(Equal("PING.EXE")) } } }) }) })
}, garden.ProcessIO{ Stdout: byteCounter, }) Expect(err).ToNot(HaveOccurred()) spawned <- true }() } for j := 0; j < numToSpawn; j++ { <-spawned } }) AfterEach(func() { err := client.Destroy(container.Handle()) Expect(err).ToNot(HaveOccurred()) }) Measure("it should not adversely affect the rest of the API", func(b Benchmarker) { var newContainer garden.Container b.Time("creating another container", func() { var err error newContainer, err = client.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) }) for i := 0; i < repeats; i++ { b.Time("getting container info ("+strconv.Itoa(repeats)+"x)", func() {
) BeforeEach(func() { var err error container, err = gdnr.Lookup("banana") Expect(err).NotTo(HaveOccurred()) }) It("asks the netwoker to forward the correct ports", func() { _, _, err := container.NetIn(externalPort, contianerPort) Expect(err).NotTo(HaveOccurred()) Expect(networker.NetInCallCount()).To(Equal(1)) actualHandle, actualExtPort, actualContainerPort := networker.NetInArgsForCall(0) Expect(actualHandle).To(Equal(container.Handle())) Expect(actualExtPort).To(Equal(externalPort)) Expect(actualContainerPort).To(Equal(contianerPort)) }) Context("when networker returns an error", func() { It("returns the error", func() { networker.NetInReturns(uint32(0), uint32(0), fmt.Errorf("error")) _, _, err := container.NetIn(externalPort, contianerPort) Expect(err).To(MatchError("error")) }) }) }) })
var _ = Describe("Rootfs container create parameter", func() { var container garden.Container var args []string BeforeEach(func() { container = nil args = []string{} }) JustBeforeEach(func() { client = startGarden(args...) }) AfterEach(func() { if container != nil { Expect(client.Destroy(container.Handle())).To(Succeed()) } }) // Temporarily pended until #102455044 is delivered to avoid slow tests PDescribe("Garbage Collection", func() { Context("when container is deleted", func() { It("the graph path is emptied", func() { container, err := client.Create(garden.ContainerSpec{RootFSPath: ""}) Expect(err).ToNot(HaveOccurred()) err = client.Destroy(container.Handle()) Expect(err).ToNot(HaveOccurred()) var size int session, err := gexec.Start(exec.Command("sh", "-c", fmt.Sprintf(" du -d0 %s", client.GraphPath)), GinkgoWriter, GinkgoWriter)
gardenParms = []string{} }) JustBeforeEach(func() { client = startGarden(gardenParms...) var err error container1, err = client.Create(garden.ContainerSpec{Network: containerNetwork1}) Expect(err).ToNot(HaveOccurred()) if len(containerNetwork2) > 0 { container2, err = client.Create(garden.ContainerSpec{Network: containerNetwork2}) Expect(err).ToNot(HaveOccurred()) } containerInterface = "w" + strconv.Itoa(GinkgoParallelNode()) + container1.Handle() + "-1" }) AfterEach(func() { if container1 != nil { err := client.Destroy(container1.Handle()) Expect(err).ToNot(HaveOccurred()) } if container2 != nil { err := client.Destroy(container2.Handle()) Expect(err).ToNot(HaveOccurred()) } }) Context("when the Network parameter is a subnet address", func() {
var container garden.Container BeforeEach(func() { var err error container, err = client.Create(garden.ContainerSpec{ Properties: garden.Properties{ "foo": "bar", "a": "b", }, }) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { client.Destroy(container.Handle()) }) Describe("info for one container", func() { It("includes the properties", func() { info, err := container.Info() Expect(err).ToNot(HaveOccurred()) Expect(info.Properties["foo"]).To(Equal("bar")) Expect(info.Properties["a"]).To(Equal("b")) Expect(info.Properties).To(HaveLen(2)) }) }) Describe("getting container properties without getting info", func() {
container = createContainer(gardenClient, garden.ContainerSpec{Privileged: false}) }) PIt("allows containers to be destroyed when wshd isn't running", func() { info, _ := container.Info() pidFile, err := os.Open(filepath.Join(info.ContainerPath, "run", "wshd.pid")) Ω(err).ShouldNot(HaveOccurred()) var pid int _, err = fmt.Fscanf(pidFile, "%d", &pid) Ω(err).ShouldNot(HaveOccurred()) _, _, err = runCommand("sudo kill -9 " + strconv.Itoa(pid)) Ω(err).ShouldNot(HaveOccurred()) err = gardenClient.Destroy(container.Handle()) Ω(err).ShouldNot(HaveOccurred()) }) It("can send TERM and KILL signals to processes (#83231270)", func() { buffer := gbytes.NewBuffer() process, err := container.Run(garden.ProcessSpec{ User: "******", Path: "sh", Args: []string{"-c", ` trap 'echo "TERM received"' TERM echo trapping while true; do echo waiting; sleep 1; done `}, }, recordedProcessIO(buffer)) Ω(err).ShouldNot(HaveOccurred())
var _ = Describe("Creating a Container", func() { var client *runner.RunningGarden var container garden.Container Context("after creating a container", func() { BeforeEach(func() { client = startGarden() var err error container, err = client.Create(garden.ContainerSpec{}) Expect(err).NotTo(HaveOccurred()) }) 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()) }) DescribeTable("placing the container in to all namespaces", func(ns string) { pid := initProcessPID(container.Handle()) hostNS, err := gexec.Start(exec.Command("ls", "-l", fmt.Sprintf("/proc/1/ns/%s", ns)), GinkgoWriter, GinkgoWriter) Expect(err).NotTo(HaveOccurred()) containerNS, err := gexec.Start(exec.Command("ls", "-l", fmt.Sprintf("/proc/%d/ns/%s", pid, ns)), GinkgoWriter, GinkgoWriter) Expect(err).NotTo(HaveOccurred()) Eventually(containerNS).Should(gexec.Exit(0)) Eventually(hostNS).Should(gexec.Exit(0))
client = startGarden() }) AfterEach(func() { Expect(client.DestroyAndStop()).To(Succeed()) }) Context("after creating a container without a specified handle", func() { var initProcPid int BeforeEach(func() { var err error container, err = client.Create(garden.ContainerSpec{}) 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)) })
gardenArgs = []string{} privileged = false }) JustBeforeEach(func() { client = startGarden(gardenArgs...) var err error container, err = client.Create(garden.ContainerSpec{Privileged: privileged}) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { if container != nil { err := client.Destroy(container.Handle()) Expect(err).ToNot(HaveOccurred()) } }) It("retains the container list", func() { restartGarden(gardenArgs...) handles := getContainerHandles() Expect(handles).To(ContainElement(container.Handle())) }) It("allows us to run processes in the same container before and after restart", func() { By("running a process before restart") runEcho(container)
"executor:owner": ownerName, }, }) Expect(err).NotTo(HaveOccurred()) container2, err = gardenClient.Create(garden.ContainerSpec{ Properties: garden.Properties{ "executor:owner": ownerName, }, }) Expect(err).NotTo(HaveOccurred()) }) It("deletes those containers (and only those containers)", func() { Eventually(func() error { _, err := gardenClient.Lookup(container1.Handle()) return err }).Should(HaveOccurred()) Eventually(func() error { _, err := gardenClient.Lookup(container2.Handle()) return err }).Should(HaveOccurred()) }) }) }) Describe("when started", func() { JustBeforeEach(func() { process = ginkgomon.Invoke(runner) })
Expect(err).ToNot(HaveOccurred()) Expect(containerizer.RunCallCount()).To(Equal(1)) id, spec, io := containerizer.RunArgsForCall(0) Expect(id).To(Equal("banana")) Expect(spec).To(Equal(origSpec)) Expect(io).To(Equal(origIO)) }) Context("when the containerizer fails to run a process", func() { BeforeEach(func() { containerizer.RunReturns(nil, errors.New("lost my banana")) }) It("returns the error", func() { _, err := container.Run(garden.ProcessSpec{}, garden.ProcessIO{}) Expect(err).To(MatchError("lost my banana")) }) }) }) Describe("destroying a container", func() { It("asks the containerizer to destroy the container", func() { Expect(gdnr.Destroy(container.Handle())).To(Succeed()) Expect(containerizer.DestroyCallCount()).To(Equal(1)) Expect(containerizer.DestroyArgsForCall(0)).To(Equal(container.Handle())) }) }) }) })
googleDNSServer := "8.8.8.8" JustBeforeEach(func() { client = startGarden() c, err = client.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) tarFile, err := os.Open("../bin/connect_to_remote_url.tar") Expect(err).ShouldNot(HaveOccurred()) defer tarFile.Close() err = c.StreamIn(garden.StreamInSpec{Path: "bin", TarStream: tarFile}) Expect(err).ShouldNot(HaveOccurred()) }) AfterEach(func() { err := client.Destroy(c.Handle()) Expect(err).ShouldNot(HaveOccurred()) }) testConnection := func(protocol, address string, port uint16) (garden.Process, error) { return c.Run(garden.ProcessSpec{ Path: "bin/connect_to_remote_url.exe", Env: []string{ fmt.Sprintf("PROTOCOL=%v", protocol), fmt.Sprintf("ADDRESS=%v:%v", address, port), }, }, garden.ProcessIO{}) } openPort := func(proto garden.Protocol, port uint16, ip string) { rule := garden.NetOutRule{
var container garden.Container var privilegedContainer bool var rootfs string JustBeforeEach(func() { client = startGarden() var err error container, err = client.Create(garden.ContainerSpec{Privileged: privilegedContainer, RootFSPath: rootfs}) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { if container != nil { Expect(client.Destroy(container.Handle())).To(Succeed()) } }) BeforeEach(func() { privilegedContainer = false rootfs = "" }) Context("when the rootfs is a symlink", func() { var symlinkDir string BeforeEach(func() { symlinkDir, err := ioutil.TempDir("", "test-symlink") Expect(err).ToNot(HaveOccurred())
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Container", func() { var container garden.Container BeforeEach(func() { var err error container, err = backend.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { Expect(backend.Destroy(container.Handle())).To(Succeed()) }) Describe("Streaming", func() { var destinationContainer garden.Container AfterEach(func() { Expect(backend.Destroy(destinationContainer.Handle())).To(Succeed()) }) It("can stream to and from container", func() { process, err := container.Run(garden.ProcessSpec{ Path: "sh", Args: []string{ "-exc", `
Context("a second container", func() { var originContainer garden.Container JustBeforeEach(func() { var err error originContainer = container container, err = client.Create(garden.ContainerSpec{ Network: subnet, }) Expect(err).NotTo(HaveOccurred()) }) AfterEach(func() { Expect(client.Destroy(originContainer.Handle())).To(Succeed()) }) It("should have the next IP address", func() { buffer := gbytes.NewBuffer() proc, err := container.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(subnet, 3)))
graceTime := 200 * time.Millisecond BeforeEach(func() { serverBackend.GraceTimeReturns(graceTime) }) It("resets the container's grace time", func() { for i := 0; i < 11; i++ { time.Sleep(graceTime / 10) call() } before := time.Now() Eventually(serverBackend.DestroyCallCount, 2*graceTime).Should(Equal(1)) Ω(serverBackend.DestroyArgsForCall(0)).Should(Equal(container.Handle())) Ω(time.Since(before)).Should(BeNumerically("~", graceTime, 30*time.Millisecond)) }) }) } itFailsWhenTheContainerIsNotFound := func(example func() error) { Context("when the container is not found", func() { It("fails", func() { serverBackend.LookupReturns(nil, errors.New("not found")) Ω(example()).Should(MatchError("not found")) }) }) }
}) Describe("IPC namespace", func() { var sharedDir string var container garden.Container BeforeEach(func() { var err error sharedDir, err = ioutil.TempDir("", "shared-mount") Expect(err).ToNot(HaveOccurred()) Expect(os.MkdirAll(sharedDir, 0755)).To(Succeed()) }) AfterEach(func() { if container != nil { Expect(client.Destroy(container.Handle())).To(Succeed()) } if sharedDir != "" { Expect(os.RemoveAll(sharedDir)).To(Succeed()) } }) It("does not allow shared memory segments in the host to be accessed by the container", func() { Expect(copyFile(shmTestBin, path.Join(sharedDir, "shm_test"))).To(Succeed()) client = startGarden() var err error container, err = client.Create(garden.ContainerSpec{ Privileged: true, BindMounts: []garden.BindMount{{ SrcPath: sharedDir,
var _ = Describe("Destroying a Container", func() { var ( client *runner.RunningGarden container garden.Container ) BeforeEach(func() { client = startGarden() }) AfterEach(func() { Expect(client.DestroyAndStop()).To(Succeed()) }) JustBeforeEach(func() { Expect(client.Destroy(container.Handle())).To(Succeed()) }) Context("when running a process", func() { var ( process garden.Process initProcPid int ) BeforeEach(func() { var err error container, err = client.Create(garden.ContainerSpec{}) Expect(err).NotTo(HaveOccurred()) initProcPid = initProcessPID(container.Handle())
func ifNamePrefix(container garden.Container) string { return "w" + strconv.Itoa(GinkgoParallelNode()) + container.Handle() }
}) 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!")
Expect(containerizer.CreateArgsForCall(0).RootFSPath).To(Equal("the-volumized-rootfs-path")) }) PIt("destroys volumes when creating fails", func() {}) Context("when a handle is specified", func() { BeforeEach(func() { spec.Handle = "the-handle" }) It("passes the handle to the containerizer", func() { Expect(containerizer.CreateArgsForCall(0).Handle).To(Equal("the-handle")) }) It("remembers the handle", func() { Expect(createdContainer.Handle()).To(Equal("the-handle")) }) PContext("and it is already in use", func() {}) }) Context("when a handle is not specified", func() { PIt("assigns a handle", func() { }) }) PContext("when creating the container fails", func() { }) Context("looking up a container and running a process", func() { var (
. "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Lifecycle", func() { var c garden.Container var err error JustBeforeEach(func() { client = startGarden() c, err = client.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) }) AfterEach(func() { err := client.Destroy(c.Handle()) Expect(err).ShouldNot(HaveOccurred()) }) Describe("process", func() { It("pid is returned", func() { tarFile, err := os.Open("../bin/consume.tar") Expect(err).ShouldNot(HaveOccurred()) defer tarFile.Close() err = c.StreamIn(garden.StreamInSpec{Path: "bin", TarStream: tarFile}) Expect(err).ShouldNot(HaveOccurred()) buf := make([]byte, 0, 1024*1024) stdout := bytes.NewBuffer(buf)
cmd := exec.Command("ip", "a") Expect(cmd.CombinedOutput()).ToNot(ContainSubstring(bridgeEvidence)) }) }) Context("when garden is shut down cleanly and restarted, and the containers are deleted", func() { BeforeEach(func() { stopGarden() client = startGarden() Expect(client.Ping()).ToNot(HaveOccurred()) cmd := exec.Command("ip", "a") Expect(cmd.CombinedOutput()).To(ContainSubstring(bridgeEvidence)) Expect(client.Destroy(ctr1.Handle())).To(Succeed()) Expect(client.Destroy(ctr2.Handle())).To(Succeed()) }) It("the subnet's bridge no longer exists", func() { cmd := exec.Command("ip", "a") Expect(cmd.CombinedOutput()).ToNot(ContainSubstring(bridgeEvidence)) }) }) Context("when garden is shut down and restarted", func() { BeforeEach(func() { stopGarden() client = startGarden() Expect(client.Ping()).ToNot(HaveOccurred())
RootFSPath: "docker:///busybox", }) Expect(err).NotTo(HaveOccurred()) response, err := http.Get(fmt.Sprintf("http://%s/debug/vars", debugAddr)) Expect(err).ToNot(HaveOccurred()) contents, err := ioutil.ReadAll(response.Body) Expect(err).ToNot(HaveOccurred()) vars = make(map[string]interface{}) Expect(json.Unmarshal(contents, &vars)).To(Succeed()) }) AfterEach(func() { Expect(client.Destroy(container.Handle())).To(Succeed()) }) It("exposes the number of loop devices", func() { Expect(vars["loopDevices"]).To(BeNumerically(">=", float64(1))) }) It("exposes the number of depot directories", func() { Expect(vars["depotDirs"]).To(Equal(float64(1))) }) It("exposes the number of backing stores", func() { Expect(vars["backingStores"]).To(Equal(float64(1))) }) Context("when the container does not have a limit", func() {
container, err = client.Create(garden.ContainerSpec{}) Expect(err).ToNot(HaveOccurred()) }) Context("when a request takes longer than the grace time", func() { It("is not destroyed after the request is over", func() { process, err := container.Run(garden.ProcessSpec{ User: "******", Path: "sleep", Args: []string{"5"}, }, garden.ProcessIO{}) Expect(err).ToNot(HaveOccurred()) Expect(process.Wait()).To(Equal(0)) _, err = container.Info() Expect(err).ToNot(HaveOccurred()) }) }) Context("when no requests are made for longer than the grace time", func() { It("is destroyed", func() { Eventually(func() error { _, err := client.Lookup(container.Handle()) return err }, 10, 1).Should(HaveOccurred()) }) }) })