mirror of
https://github.com/bcicen/ctop.git
synced 2025-12-06 15:16:41 +08:00
Merge branch 'exec' of https://github.com/fr05t1k/ctop into fr05t1k-exec
This commit is contained in:
@@ -3,6 +3,9 @@ package manager
|
||||
import (
|
||||
"fmt"
|
||||
api "github.com/fsouza/go-dockerclient"
|
||||
"github.com/pkg/errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Docker struct {
|
||||
@@ -17,6 +20,85 @@ func NewDocker(client *api.Client, id string) *Docker {
|
||||
}
|
||||
}
|
||||
|
||||
// Do not allow to close reader (i.e. /dev/stdin which docker client tries to close after command execution)
|
||||
type noClosableReader struct {
|
||||
wrappedReader io.Reader
|
||||
}
|
||||
|
||||
func (w *noClosableReader) Read(p []byte) (n int, err error) {
|
||||
return w.wrappedReader.Read(p)
|
||||
}
|
||||
|
||||
const (
|
||||
STDIN = 0
|
||||
STDOUT = 1
|
||||
STDERR = 2
|
||||
)
|
||||
|
||||
var (
|
||||
wrongFrameFormat = errors.New("Wrong frame format")
|
||||
)
|
||||
|
||||
// A frame has a Header and a Payload
|
||||
// Header: [8]byte{STREAM_TYPE, 0, 0, 0, SIZE1, SIZE2, SIZE3, SIZE4}
|
||||
// STREAM_TYPE can be:
|
||||
// 0: stdin (is written on stdout)
|
||||
// 1: stdout
|
||||
// 2: stderr
|
||||
// SIZE1, SIZE2, SIZE3, SIZE4 are the four bytes of the uint32 size encoded as big endian.
|
||||
// But we don't use size, because we don't need to find the end of frame.
|
||||
type frameWriter struct {
|
||||
stdout io.Writer
|
||||
stderr io.Writer
|
||||
stdin io.Writer
|
||||
}
|
||||
|
||||
func (w *frameWriter) Write(p []byte) (n int, err error) {
|
||||
if len(p) > 8 {
|
||||
var targetWriter io.Writer
|
||||
switch p[0] {
|
||||
case STDIN:
|
||||
targetWriter = w.stdin
|
||||
break
|
||||
case STDOUT:
|
||||
targetWriter = w.stdout
|
||||
break
|
||||
case STDERR:
|
||||
targetWriter = w.stderr
|
||||
break
|
||||
default:
|
||||
return 0, wrongFrameFormat
|
||||
}
|
||||
|
||||
n, err := targetWriter.Write(p[8:])
|
||||
return n + 8, err
|
||||
}
|
||||
|
||||
return 0, wrongFrameFormat
|
||||
}
|
||||
|
||||
func (dc *Docker) Exec(cmd []string) error {
|
||||
execCmd, err := dc.client.CreateExec(api.CreateExecOptions{
|
||||
AttachStdin: true,
|
||||
AttachStdout: true,
|
||||
AttachStderr: true,
|
||||
Cmd: cmd,
|
||||
Container: dc.id,
|
||||
Tty: true,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return dc.client.StartExec(execCmd.ID, api.StartExecOptions{
|
||||
InputStream: &noClosableReader{os.Stdin},
|
||||
OutputStream: &frameWriter{os.Stdout, os.Stderr, os.Stdin},
|
||||
ErrorStream: os.Stderr,
|
||||
RawTerminal: true,
|
||||
})
|
||||
}
|
||||
|
||||
func (dc *Docker) Start() error {
|
||||
c, err := dc.client.InspectContainer(dc.id)
|
||||
if err != nil {
|
||||
|
||||
@@ -7,4 +7,5 @@ type Manager interface {
|
||||
Pause() error
|
||||
Unpause() error
|
||||
Restart() error
|
||||
Exec(cmd []string) error
|
||||
}
|
||||
|
||||
@@ -29,3 +29,7 @@ func (m *Mock) Unpause() error {
|
||||
func (m *Mock) Restart() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Mock) Exec(cmd []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -29,3 +29,7 @@ func (rc *Runc) Unpause() error {
|
||||
func (rc *Runc) Restart() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rc *Runc) Exec(cmd []string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user