func (s *GardenServer) streamInput(decoder *json.Decoder, in *io.PipeWriter, process garden.Process, connCloseCh chan struct{}) { for { var payload transport.ProcessPayload err := decoder.Decode(&payload) if err != nil { close(connCloseCh) in.CloseWithError(errors.New("Connection closed")) return } switch { case payload.TTY != nil: process.SetTTY(*payload.TTY) case payload.Source != nil: if payload.Data == nil { in.Close() return } else { _, err := in.Write([]byte(*payload.Data)) if err != nil { return } } case payload.Signal != nil: s.logger.Info("stream-input-process-signal", lager.Data{"payload": payload}) switch *payload.Signal { case garden.SignalKill: err = process.Signal(garden.SignalKill) if err != nil { s.logger.Error("stream-input-process-signal-kill-failed", err, lager.Data{"payload": payload}) } case garden.SignalTerminate: err = process.Signal(garden.SignalTerminate) if err != nil { s.logger.Error("stream-input-process-signal-terminate-failed", err, lager.Data{"payload": payload}) } default: s.logger.Error("stream-input-unknown-process-payload-signal", nil, lager.Data{"payload": payload}) in.Close() return } default: s.logger.Error("stream-input-unknown-process-payload", nil, lager.Data{"payload": payload}) in.Close() return } } }
AfterEach(func() { Expect(client.DestroyAndStop()).To(Succeed()) }) const ( subnetName string = "177-100-10-0" ) Context("when a container is created and then garden is restarted", func() { var ( container garden.Container hostNetInPort uint32 externalIP string interfacePrefix string propertiesDir string existingProc garden.Process containerSpec garden.ContainerSpec restartArgs []string gracefulShutdown bool ) BeforeEach(func() { var err error propertiesDir, err = ioutil.TempDir("", "props") Expect(err).NotTo(HaveOccurred()) args = append(args, "--properties-path", path.Join(propertiesDir, "props.json")) containerSpec = garden.ContainerSpec{ Network: "177.100.10.30/30", }
Stdout: io.MultiWriter(GinkgoWriter, stdout), Stderr: GinkgoWriter, }) Expect(err).ToNot(HaveOccurred()) Eventually(stdout).Should(gbytes.Say("waiting")) Expect(process.Signal(garden.SignalTerminate)).To(Succeed()) Expect(process.Wait()).NotTo(BeZero()) checkProcessIsGone(container, "sh -c while") close(done) }, 10.0) Context("when killing a process that does not use streaming", func() { var process garden.Process var buff *gbytes.Buffer JustBeforeEach(func() { var err error buff = gbytes.NewBuffer() process, err = container.Run(garden.ProcessSpec{ User: "******", Path: "sh", Args: []string{ "-c", "while true; do echo stillhere; sleep 1; done", }, }, garden.ProcessIO{Stdout: buff}) Expect(err).ToNot(HaveOccurred())
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 } } }