func flushProcess(conn net.Conn, process garden.Process, stdout <-chan []byte, stderr <-chan []byte) { 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, }) default: return } } }
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 (conn RetryableConnection) Run(handle string, processSpec garden.ProcessSpec, processIO garden.ProcessIO) (garden.Process, error) { var innerProcess garden.Process err := conn.retry(func() error { var err error innerProcess, err = conn.Connection.Run(handle, processSpec, processIO) return err }) if err != nil { return nil, err } return &retryableProcess{ Process: innerProcess, rehydrate: func() (garden.Process, error) { return conn.Attach(handle, innerProcess.ID(), processIO) }, }, nil }
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 } } }