Example #1
0
func (s *rpcServer) Enter(inStream pb.Kurma_EnterServer) error {
	s.log.Debug("Received enter request")

	// read the first chunk to make sure its real and get the container ID
	chunk, err := inStream.Recv()
	if err != nil {
		return err
	}

	// create the outbound stream
	outStream, err := s.client.Enter(inStream.Context())
	if err != nil {
		return err
	}

	// Create our inbound streams
	inWriter := pb.NewByteStreamWriter(inStream, chunk.StreamId)
	inReader := pb.NewByteStreamReader(inStream, nil)

	// Create our outbound streams
	outWriter := pb.NewByteStreamWriter(outStream, chunk.StreamId)
	outReader := pb.NewByteStreamReader(outStream, nil)

	// write the first byte to the backend so it is initialized
	if _, err := outWriter.Write(nil); err != nil {
		return err
	}

	// stream between!
	go io.Copy(outWriter, inReader)
	io.Copy(inWriter, outReader)
	outStream.CloseSend()
	return nil
}
Example #2
0
func (s *rpcServer) Enter(stream pb.Kurma_EnterServer) error {
	s.log.Debug("Received enter request")

	// Receive the first chunk so we can get the stream ID, which will be the UUID
	// of the container. The byte portion will be blank, the client always sends a
	// chunk first so the UUID is available immediately.
	chunk, err := stream.Recv()
	if err != nil {
		return err
	}

	// get the container
	container := s.manager.Container(chunk.StreamId)
	if container == nil {
		return fmt.Errorf("specified container not found")
	}

	// configure the io.Reader/Writer for the transport
	w := pb.NewByteStreamWriter(stream, chunk.StreamId)
	r := pb.NewByteStreamReader(stream, nil)

	// create a pty, which we'll use for the process entering the container and
	// copy the data back up the transport.
	master, slave, err := pty.Open()
	if err != nil {
		return err
	}
	defer func() {
		slave.Close()
		master.Close()
	}()
	go io.Copy(w, master)
	go io.Copy(master, r)

	// enter into the container
	if err := container.Enter(slave); err != nil {
		return err
	}
	s.log.Debugf("Enter request finished")
	return nil
}