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 } } }
func (c *checker) wait(logger lager.Logger, proc garden.Process) (int, error) { logger = logger.Session("wait") logger.Debug("starting") defer logger.Debug("finished") var exitCode int err := retryOnFail(c.retryInterval, func(attempt uint) (waitErr error) { exitCode, waitErr = proc.Wait() if waitErr != nil { logger.Error("failed", waitErr, lager.Data{"attempt": attempt}) return waitErr } logger.Debug("succeeded", lager.Data{"attempt": attempt}) return nil }) return exitCode, err }
func (resource *resource) runScript( path string, args []string, input interface{}, output interface{}, logDest io.Writer, inputSource ArtifactSource, inputDestination ArtifactDestination, recoverable bool, ) ifrit.Runner { return ifrit.RunFunc(func(signals <-chan os.Signal, ready chan<- struct{}) error { request, err := json.Marshal(input) if err != nil { return err } if recoverable { result, err := resource.container.Property(resourceResultPropertyName) if err == nil { return json.Unmarshal([]byte(result), &output) } } stdout := new(bytes.Buffer) stderr := new(bytes.Buffer) processIO := garden.ProcessIO{ Stdin: bytes.NewBuffer(request), Stdout: stdout, } if logDest != nil { processIO.Stderr = logDest } else { processIO.Stderr = stderr } var process garden.Process var processIDProp string if recoverable { processIDProp, err = resource.container.Property(resourceProcessIDPropertyName) if err != nil { processIDProp = "" } } if processIDProp != "" { var processID uint32 _, err = fmt.Sscanf(processIDProp, "%d", &processID) if err != nil { return err } process, err = resource.container.Attach(processID, processIO) if err != nil { return err } } else { if inputSource != nil { err := inputSource.StreamTo(inputDestination) if err != nil { return err } } process, err = resource.container.Run(garden.ProcessSpec{ Path: path, Args: args, User: "******", }, processIO) if err != nil { return err } if recoverable { processIDValue := fmt.Sprintf("%d", process.ID()) err := resource.container.SetProperty(resourceProcessIDPropertyName, processIDValue) if err != nil { return err } } } close(ready) statusCh := make(chan int, 1) errCh := make(chan error, 1) go func() { status, err := process.Wait() if err != nil { errCh <- err } else { statusCh <- status } }() select { case status := <-statusCh: if status != 0 { return ErrResourceScriptFailed{ Path: path, Args: args, ExitStatus: status, Stderr: stderr.String(), } } if recoverable { err := resource.container.SetProperty(resourceResultPropertyName, stdout.String()) if err != nil { return err } } return json.Unmarshal(stdout.Bytes(), output) case err := <-errCh: return err case <-signals: resource.container.Stop(false) return ErrAborted } }) }
func (s *GardenServer) streamProcess(logger lager.Logger, conn net.Conn, process garden.Process, stdout <-chan []byte, stderr <-chan []byte, stdinPipe *io.PipeWriter) { 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 } }() stdoutSource := transport.Stdout stderrSource := transport.Stderr for { select { case data := <-stdout: d := string(data) transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), Source: &stdoutSource, Data: &d, }) case data := <-stderr: d := string(data) transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), Source: &stderrSource, Data: &d, }) case status := <-statusCh: flushProcess(conn, process, stdout, stderr) transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), ExitStatus: &status, }) stdinPipe.Close() return case err := <-errCh: flushProcess(conn, process, stdout, stderr) 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 } } }
errs := make(chan error, 1) errs <- fmt.Errorf("connection: decode failed: %s", io.EOF) close(errs) fakeProcess.WaitStub = func() (int, error) { err := <-errs if err == nil { return 42, nil } return 0, err } }) It("reattaches on EOF", func() { result, err := process.Wait() Ω(err).ShouldNot(HaveOccurred()) Ω(result).Should(Equal(42)) Ω(innerConnection.AttachCallCount()).Should(Equal(2)) handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(1) Ω(handle).Should(Equal("la-contineur")) Ω(processID).Should(Equal(uint32(6))) Ω(calledProcessIO).Should(Equal(processIO)) }) }) Describe("Signal", func() { BeforeEach(func() { errs := make(chan error, 1) errs <- io.EOF
errs := make(chan error, 1) errs <- fmt.Errorf("connection: decode failed: %s", io.EOF) close(errs) fakeProcess.WaitStub = func() (int, error) { err := <-errs if err == nil { return 42, nil } return 0, err } }) It("reattaches on EOF", func() { result, err := process.Wait() Expect(err).NotTo(HaveOccurred()) Expect(result).To(Equal(42)) Expect(innerConnection.AttachCallCount()).To(Equal(2)) handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(1) Expect(handle).To(Equal("la-contineur")) Expect(processID).To(Equal("process-id")) Expect(calledProcessIO).To(Equal(processIO)) }) }) Describe("Signal", func() { BeforeEach(func() { errs := make(chan error, 1) errs <- io.EOF