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 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) }
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": "process-handle", "stream_id": "123", }) var payload map[string]interface{} err = decoder.Decode(&payload) Ω(err).ShouldNot(HaveOccurred()) Ω(payload).Should(Equal(map[string]interface{}{ "process_id": "process-handle", "source": float64(transport.Stdin), "data": "stdin data", })) stdInContent <- payload["data"].(string) transport.WriteMessage(conn, map[string]interface{}{ "process_id": "process-handle",
func (s *GardenServer) writeResponse(w http.ResponseWriter, msg interface{}) { w.Header().Set("Content-Type", "application/json") transport.WriteMessage(w, msg) }
func (s *GardenServer) handleAttach(w http.ResponseWriter, r *http.Request) { handle := r.FormValue(":handle") hLog := s.logger.Session("attach", lager.Data{ "handle": handle, }) processID := r.FormValue(":pid") 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), }) connCloseCh := make(chan struct{}, 1) go s.streamInput(json.NewDecoder(br), stdinW, process, connCloseCh) s.streamProcess(hLog, conn, process, stdinW, connCloseCh) }
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), }) connCloseCh := make(chan struct{}, 1) go s.streamInput(json.NewDecoder(br), stdinW, process, connCloseCh) s.streamProcess(hLog, conn, process, stdinW, connCloseCh) }