func (s *GardenServer) streamProcess(logger lager.Logger, conn net.Conn, process garden.Process, stdinPipe *io.PipeWriter, connCloseCh chan struct{}) { statusCh := make(chan int, 1) errCh := make(chan error, 1) go func() { status, err := process.Wait() if err != nil { logger.Error("wait-failed", err, lager.Data{ "id": process.ID(), }) errCh <- err } else { logger.Info("exited", lager.Data{ "status": status, "id": process.ID(), }) statusCh <- status } }() for { select { case status := <-statusCh: transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), ExitStatus: &status, }) stdinPipe.Close() return case err := <-errCh: e := err.Error() transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), Error: &e, }) stdinPipe.Close() return case <-s.stopping: logger.Debug("detaching", lager.Data{ "id": process.ID(), }) return case <-connCloseCh: return } } }
}, garden.ProcessIO{ Stdout: io.MultiWriter(GinkgoWriter, out), Stderr: io.MultiWriter(GinkgoWriter, out), }) Expect(err).NotTo(HaveOccurred()) exitCode, err := proc.Wait() Expect(err).NotTo(HaveOccurred()) Expect(exitCode).To(Equal(12)) Expect(out).To(gbytes.Say("hello")) }) It("can reattach to processes that are still running", func() { out := gbytes.NewBuffer() procId := existingProc.ID() process, err := container.Attach(procId, garden.ProcessIO{ Stdout: io.MultiWriter(GinkgoWriter, out), Stderr: io.MultiWriter(GinkgoWriter, out), }) Expect(err).NotTo(HaveOccurred()) Eventually(out).Should(gbytes.Say("hello")) Expect(process.Signal(garden.SignalKill)).To(Succeed()) exited := make(chan struct{}) go func() { process.Wait() close(exited) }()