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 (c *connection) Run(handle string, spec garden.ProcessSpec, processIO garden.ProcessIO) (garden.Process, error) { reqBody := new(bytes.Buffer) err := transport.WriteMessage(reqBody, spec) if err != nil { return nil, err } conn, br, err := c.doHijack( routes.Run, reqBody, rata.Params{ "handle": handle, }, nil, "application/json", ) if err != nil { return nil, err } decoder := json.NewDecoder(br) firstResponse := &transport.ProcessPayload{} err = decoder.Decode(firstResponse) if err != nil { return nil, err } p := newProcess(firstResponse.ProcessID, conn) go p.streamPayloads(decoder, processIO) return p, nil }
func marshalProto(messages ...interface{}) string { result := new(bytes.Buffer) for _, msg := range messages { err := transport.WriteMessage(result, msg) Ω(err).ShouldNot(HaveOccurred()) } return result.String() }
func (s *processStream) sendPayload(payload interface{}) error { s.Lock() err := transport.WriteMessage(s.conn, payload) if err != nil { s.Unlock() return err } s.Unlock() return nil }
func (c *connection) do( handler string, req, res interface{}, params rata.Params, query url.Values, ) error { var body io.Reader if req != nil { buf := new(bytes.Buffer) err := transport.WriteMessage(buf, req) if err != nil { return err } body = buf } contentType := "" if req != nil { contentType = "application/json" } response, err := c.hijacker.Stream( handler, body, params, query, contentType, ) if err != nil { return err } defer response.Close() return json.NewDecoder(response).Decode(res) }
func (c *connection) Run(handle string, spec garden.ProcessSpec, processIO garden.ProcessIO) (garden.Process, error) { reqBody := new(bytes.Buffer) err := transport.WriteMessage(reqBody, spec) if err != nil { return nil, err } hijackedConn, hijackedResponseReader, err := c.hijacker.Hijack( routes.Run, reqBody, rata.Params{ "handle": handle, }, nil, "application/json", ) if err != nil { return nil, fmt.Errorf("hijack: %s", err) } return c.streamProcess(handle, processIO, hijackedConn, hijackedResponseReader) }
func (c *connection) Run(handle string, spec garden.ProcessSpec, processIO garden.ProcessIO) (garden.Process, error) { reqBody := new(bytes.Buffer) err := transport.WriteMessage(reqBody, spec) if err != nil { return nil, err } conn, br, err := c.doHijack( routes.Run, reqBody, rata.Params{ "handle": handle, }, nil, "application/json", ) if err != nil { return nil, err } return c.streamProcess(handle, processIO, conn, br) }
func (s *GardenServer) handleAttach(w http.ResponseWriter, r *http.Request) { handle := r.FormValue(":handle") var processID uint32 hLog := s.logger.Session("attach", lager.Data{ "handle": handle, }) _, err := fmt.Sscanf(r.FormValue(":pid"), "%d", &processID) if err != nil { s.writeError(w, err, hLog) return } container, err := s.backend.Lookup(handle) if err != nil { s.writeError(w, err, hLog) return } s.bomberman.Pause(container.Handle()) defer s.bomberman.Unpause(container.Handle()) stdout := make(chan []byte, 1000) stderr := make(chan []byte, 1000) stdinR, stdinW := io.Pipe() processIO := garden.ProcessIO{ Stdin: stdinR, Stdout: &chanWriter{stdout}, Stderr: &chanWriter{stderr}, } hLog.Debug("attaching", lager.Data{ "id": processID, }) process, err := container.Attach(processID, processIO) if err != nil { s.writeError(w, err, hLog) stdinW.Close() return } hLog.Info("attached", lager.Data{ "id": process.ID(), }) streamID := s.streamer.Stream(stdout, stderr) defer s.streamer.Stop(streamID) w.WriteHeader(http.StatusOK) w.Header().Set("Content-Type", "application/json") conn, br, err := w.(http.Hijacker).Hijack() if err != nil { s.writeError(w, err, hLog) stdinW.Close() return } defer conn.Close() transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), StreamID: string(streamID), }) go s.streamInput(json.NewDecoder(br), stdinW, process) s.streamProcess(hLog, conn, process, stdinW) }
func (s *GardenServer) handleRun(w http.ResponseWriter, r *http.Request) { handle := r.FormValue(":handle") hLog := s.logger.Session("run", lager.Data{ "handle": handle, }) var request garden.ProcessSpec if !s.readRequest(&request, w, r) { return } info := processDebugInfo{ Path: request.Path, Dir: request.Dir, User: request.User, Limits: request.Limits, TTY: request.TTY, } container, err := s.backend.Lookup(handle) if err != nil { s.writeError(w, err, hLog) return } s.bomberman.Pause(container.Handle()) defer s.bomberman.Unpause(container.Handle()) hLog.Debug("running", lager.Data{ "spec": info, }) stdout := make(chan []byte, 1000) stderr := make(chan []byte, 1000) stdinR, stdinW := io.Pipe() processIO := garden.ProcessIO{ Stdin: stdinR, Stdout: &chanWriter{stdout}, Stderr: &chanWriter{stderr}, } process, err := container.Run(request, processIO) if err != nil { s.writeError(w, err, hLog) return } hLog.Info("spawned", lager.Data{ "spec": info, "id": process.ID(), }) streamID := s.streamer.Stream(stdout, stderr) defer s.streamer.Stop(streamID) w.WriteHeader(http.StatusCreated) w.Header().Set("Content-Type", "application/json") conn, br, err := w.(http.Hijacker).Hijack() if err != nil { s.writeError(w, err, hLog) stdinW.Close() return } defer conn.Close() transport.WriteMessage(conn, &transport.ProcessPayload{ ProcessID: process.ID(), StreamID: string(streamID), }) go s.streamInput(json.NewDecoder(br), stdinW, process) s.streamProcess(hLog, conn, process, stdinW) }
func (s *GardenServer) writeResponse(w http.ResponseWriter, msg interface{}) { w.Header().Set("Content-Type", "application/json") transport.WriteMessage(w, msg) }
server.AppendHandlers( ghttp.CombineHandlers( ghttp.VerifyRequest("POST", "/containers/foo-handle/processes"), ghttp.VerifyJSONRepresenting(spec), func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) conn, br, err := w.(http.Hijacker).Hijack() Ω(err).ShouldNot(HaveOccurred()) defer conn.Close() decoder := json.NewDecoder(br) transport.WriteMessage(conn, map[string]interface{}{ "process_id": 42, "stream_id": "123", }) var payload map[string]interface{} err = decoder.Decode(&payload) Ω(err).ShouldNot(HaveOccurred()) Ω(payload).Should(Equal(map[string]interface{}{ "process_id": float64(42), "source": float64(transport.Stdin), "data": "stdin data", })) stdInContent <- payload["data"].(string) transport.WriteMessage(conn, map[string]interface{}{ "process_id": 42,
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 } } }