Merge pull request #5634 from hashicorp/f-nomad-exec-parts-03-executors
nomad exec part 3: executor based drivers
This commit is contained in:
commit
f58932afe9
|
@ -530,3 +530,22 @@ func (d *Driver) ExecTask(taskID string, cmd []string, timeout time.Duration) (*
|
|||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ drivers.ExecTaskStreamingRawDriver = (*Driver)(nil)
|
||||
|
||||
func (d *Driver) ExecTaskStreamingRaw(ctx context.Context,
|
||||
taskID string,
|
||||
command []string,
|
||||
tty bool,
|
||||
stream drivers.ExecTaskStream) error {
|
||||
|
||||
if len(command) == 0 {
|
||||
return fmt.Errorf("error cmd must have atleast one value")
|
||||
}
|
||||
handle, ok := d.tasks.Get(taskID)
|
||||
if !ok {
|
||||
return drivers.ErrTaskNotFound
|
||||
}
|
||||
|
||||
return handle.exec.ExecStreaming(ctx, command, tty, stream)
|
||||
}
|
||||
|
|
|
@ -77,3 +77,33 @@ func TestExecDriver_StartWaitStop(t *testing.T) {
|
|||
|
||||
require.NoError(harness.DestroyTask(task.ID, true))
|
||||
}
|
||||
|
||||
func TestExec_ExecTaskStreaming(t *testing.T) {
|
||||
t.Parallel()
|
||||
require := require.New(t)
|
||||
|
||||
d := NewExecDriver(testlog.HCLogger(t))
|
||||
harness := dtestutil.NewDriverHarness(t, d)
|
||||
defer harness.Kill()
|
||||
|
||||
task := &drivers.TaskConfig{
|
||||
ID: uuid.Generate(),
|
||||
Name: "sleep",
|
||||
}
|
||||
|
||||
cleanup := harness.MkAllocDir(task, false)
|
||||
defer cleanup()
|
||||
|
||||
tc := &TaskConfig{
|
||||
Command: "/bin/sleep",
|
||||
Args: []string{"9000"},
|
||||
}
|
||||
require.NoError(task.EncodeConcreteDriverConfig(&tc))
|
||||
|
||||
_, _, err := harness.StartTask(task)
|
||||
require.NoError(err)
|
||||
defer d.DestroyTask(task.ID, true)
|
||||
|
||||
dtestutil.ExecTaskStreamingConformanceTests(t, harness, task.ID)
|
||||
|
||||
}
|
||||
|
|
|
@ -554,6 +554,25 @@ func (d *Driver) ExecTask(taskID string, cmd []string, timeout time.Duration) (*
|
|||
}, nil
|
||||
}
|
||||
|
||||
var _ drivers.ExecTaskStreamingRawDriver = (*Driver)(nil)
|
||||
|
||||
func (d *Driver) ExecTaskStreamingRaw(ctx context.Context,
|
||||
taskID string,
|
||||
command []string,
|
||||
tty bool,
|
||||
stream drivers.ExecTaskStream) error {
|
||||
|
||||
if len(command) == 0 {
|
||||
return fmt.Errorf("error cmd must have atleast one value")
|
||||
}
|
||||
handle, ok := d.tasks.Get(taskID)
|
||||
if !ok {
|
||||
return drivers.ErrTaskNotFound
|
||||
}
|
||||
|
||||
return handle.exec.ExecStreaming(ctx, command, tty, stream)
|
||||
}
|
||||
|
||||
// GetAbsolutePath returns the absolute path of the passed binary by resolving
|
||||
// it in the path and following symlinks.
|
||||
func GetAbsolutePath(bin string) (string, error) {
|
||||
|
|
|
@ -243,6 +243,35 @@ func TestJavaCmdArgs(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestJavaDriver_ExecTaskStreaming(t *testing.T) {
|
||||
javaCompatible(t)
|
||||
if !testutil.IsCI() {
|
||||
t.Parallel()
|
||||
}
|
||||
|
||||
require := require.New(t)
|
||||
d := NewDriver(testlog.HCLogger(t))
|
||||
harness := dtestutil.NewDriverHarness(t, d)
|
||||
defer harness.Kill()
|
||||
|
||||
tc := &TaskConfig{
|
||||
Class: "Hello",
|
||||
Args: []string{"900"},
|
||||
}
|
||||
task := basicTask(t, "demo-app", tc)
|
||||
|
||||
cleanup := harness.MkAllocDir(task, true)
|
||||
defer cleanup()
|
||||
|
||||
copyFile("./test-resources/Hello.class", filepath.Join(task.TaskDir().Dir, "Hello.class"), t)
|
||||
|
||||
_, _, err := harness.StartTask(task)
|
||||
require.NoError(err)
|
||||
defer d.DestroyTask(task.ID, true)
|
||||
|
||||
dtestutil.ExecTaskStreamingConformanceTests(t, harness, task.ID)
|
||||
|
||||
}
|
||||
func basicTask(t *testing.T, name string, taskConfig *TaskConfig) *drivers.TaskConfig {
|
||||
t.Helper()
|
||||
|
||||
|
|
|
@ -521,3 +521,22 @@ func (d *Driver) ExecTask(taskID string, cmd []string, timeout time.Duration) (*
|
|||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var _ drivers.ExecTaskStreamingRawDriver = (*Driver)(nil)
|
||||
|
||||
func (d *Driver) ExecTaskStreamingRaw(ctx context.Context,
|
||||
taskID string,
|
||||
command []string,
|
||||
tty bool,
|
||||
stream drivers.ExecTaskStream) error {
|
||||
|
||||
if len(command) == 0 {
|
||||
return fmt.Errorf("error cmd must have at least one value")
|
||||
}
|
||||
handle, ok := d.tasks.Get(taskID)
|
||||
if !ok {
|
||||
return drivers.ErrTaskNotFound
|
||||
}
|
||||
|
||||
return handle.exec.ExecStreaming(ctx, command, tty, stream)
|
||||
}
|
||||
|
|
|
@ -196,3 +196,37 @@ func TestRawExecDriver_StartWaitStop(t *testing.T) {
|
|||
|
||||
require.NoError(harness.DestroyTask(task.ID, true))
|
||||
}
|
||||
|
||||
func TestRawExec_ExecTaskStreaming(t *testing.T) {
|
||||
t.Parallel()
|
||||
if runtime.GOOS == "darwin" {
|
||||
t.Skip("skip running exec tasks on darwin as darwin has restrictions on starting tty shells")
|
||||
}
|
||||
require := require.New(t)
|
||||
|
||||
d := NewRawExecDriver(testlog.HCLogger(t))
|
||||
harness := dtestutil.NewDriverHarness(t, d)
|
||||
defer harness.Kill()
|
||||
|
||||
task := &drivers.TaskConfig{
|
||||
ID: uuid.Generate(),
|
||||
Name: "sleep",
|
||||
}
|
||||
|
||||
cleanup := harness.MkAllocDir(task, false)
|
||||
defer cleanup()
|
||||
|
||||
tc := &TaskConfig{
|
||||
Command: testtask.Path(),
|
||||
Args: []string{"sleep", "9000s"},
|
||||
}
|
||||
require.NoError(task.EncodeConcreteDriverConfig(&tc))
|
||||
testtask.SetTaskConfigEnv(task)
|
||||
|
||||
_, _, err := harness.StartTask(task)
|
||||
require.NoError(err)
|
||||
defer d.DestroyTask(task.ID, true)
|
||||
|
||||
dtestutil.ExecTaskStreamingConformanceTests(t, harness, task.ID)
|
||||
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ import (
|
|||
hclog "github.com/hashicorp/go-hclog"
|
||||
cstructs "github.com/hashicorp/nomad/client/structs"
|
||||
"github.com/hashicorp/nomad/drivers/shared/executor/proto"
|
||||
"github.com/hashicorp/nomad/helper/pluginutils/grpcutils"
|
||||
"github.com/hashicorp/nomad/plugins/drivers"
|
||||
dproto "github.com/hashicorp/nomad/plugins/drivers/proto"
|
||||
)
|
||||
|
||||
var _ Executor = (*grpcExecutorClient)(nil)
|
||||
|
@ -181,3 +183,74 @@ func (c *grpcExecutorClient) Exec(deadline time.Time, cmd string, args []string)
|
|||
|
||||
return resp.Output, int(resp.ExitCode), nil
|
||||
}
|
||||
|
||||
func (d *grpcExecutorClient) ExecStreaming(ctx context.Context,
|
||||
command []string,
|
||||
tty bool,
|
||||
execStream drivers.ExecTaskStream) error {
|
||||
|
||||
err := d.execStreaming(ctx, command, tty, execStream)
|
||||
if err != nil {
|
||||
return grpcutils.HandleGrpcErr(err, d.doneCtx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *grpcExecutorClient) execStreaming(ctx context.Context,
|
||||
command []string,
|
||||
tty bool,
|
||||
execStream drivers.ExecTaskStream) error {
|
||||
|
||||
stream, err := d.client.ExecStreaming(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = stream.Send(&dproto.ExecTaskStreamingRequest{
|
||||
Setup: &dproto.ExecTaskStreamingRequest_Setup{
|
||||
Command: command,
|
||||
Tty: tty,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
go func() {
|
||||
for {
|
||||
m, err := execStream.Recv()
|
||||
if err == io.EOF {
|
||||
return
|
||||
} else if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
if err := stream.Send(m); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-errCh:
|
||||
return err
|
||||
default:
|
||||
}
|
||||
|
||||
m, err := stream.Recv()
|
||||
if err == io.EOF {
|
||||
return nil
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := execStream.Send(m); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,287 @@
|
|||
package executor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
hclog "github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/nomad/plugins/drivers"
|
||||
dproto "github.com/hashicorp/nomad/plugins/drivers/proto"
|
||||
)
|
||||
|
||||
// execHelper is a convenient wrapper for starting and executing commands, and handling their output
|
||||
type execHelper struct {
|
||||
logger hclog.Logger
|
||||
|
||||
// newTerminal function creates a tty appropriate for the command
|
||||
// The returned pty end of tty function is to be called after process start.
|
||||
newTerminal func() (pty func() (*os.File, error), tty *os.File, err error)
|
||||
|
||||
// setTTY is a callback to configure the command with slave end of the tty of the terminal, when tty is enabled
|
||||
setTTY func(tty *os.File) error
|
||||
|
||||
// setTTY is a callback to configure the command with std{in|out|err}, when tty is disabled
|
||||
setIO func(stdin io.Reader, stdout, stderr io.Writer) error
|
||||
|
||||
// processStart starts the process, like `exec.Cmd.Start()`
|
||||
processStart func() error
|
||||
|
||||
// processWait blocks until command terminates and returns its final state
|
||||
processWait func() (*os.ProcessState, error)
|
||||
}
|
||||
|
||||
func (e *execHelper) run(ctx context.Context, tty bool, stream drivers.ExecTaskStream) error {
|
||||
if tty {
|
||||
return e.runTTY(ctx, stream)
|
||||
}
|
||||
return e.runNoTTY(ctx, stream)
|
||||
}
|
||||
|
||||
func (e *execHelper) runTTY(ctx context.Context, stream drivers.ExecTaskStream) error {
|
||||
ptyF, tty, err := e.newTerminal()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open a tty: %v", err)
|
||||
}
|
||||
defer tty.Close()
|
||||
|
||||
if err := e.setTTY(tty); err != nil {
|
||||
return fmt.Errorf("failed to set command tty: %v", err)
|
||||
}
|
||||
if err := e.processStart(); err != nil {
|
||||
return fmt.Errorf("failed to start command: %v", err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, 3)
|
||||
|
||||
pty, err := ptyF()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get pty: %v", err)
|
||||
}
|
||||
|
||||
defer pty.Close()
|
||||
wg.Add(1)
|
||||
go handleStdin(e.logger, pty, stream, errCh)
|
||||
// when tty is on, stdout and stderr point to the same pty so only read once
|
||||
go handleStdout(e.logger, pty, &wg, stream.Send, errCh)
|
||||
|
||||
ps, err := e.processWait()
|
||||
|
||||
// force close streams to close out the stream copying goroutines
|
||||
tty.Close()
|
||||
|
||||
// wait until we get all process output
|
||||
wg.Wait()
|
||||
|
||||
// wait to flush out output
|
||||
stream.Send(cmdExitResult(ps, err))
|
||||
|
||||
select {
|
||||
case cerr := <-errCh:
|
||||
return cerr
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func (e *execHelper) runNoTTY(ctx context.Context, stream drivers.ExecTaskStream) error {
|
||||
var sendLock sync.Mutex
|
||||
send := func(v *drivers.ExecTaskStreamingResponseMsg) error {
|
||||
sendLock.Lock()
|
||||
defer sendLock.Unlock()
|
||||
|
||||
return stream.Send(v)
|
||||
}
|
||||
|
||||
stdinPr, stdinPw := io.Pipe()
|
||||
stdoutPr, stdoutPw := io.Pipe()
|
||||
stderrPr, stderrPw := io.Pipe()
|
||||
|
||||
defer stdoutPw.Close()
|
||||
defer stderrPw.Close()
|
||||
|
||||
if err := e.setIO(stdinPr, stdoutPw, stderrPw); err != nil {
|
||||
return fmt.Errorf("failed to set command io: %v", err)
|
||||
}
|
||||
|
||||
if err := e.processStart(); err != nil {
|
||||
return fmt.Errorf("failed to start command: %v", err)
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errCh := make(chan error, 3)
|
||||
|
||||
wg.Add(2)
|
||||
go handleStdin(e.logger, stdinPw, stream, errCh)
|
||||
go handleStdout(e.logger, stdoutPr, &wg, send, errCh)
|
||||
go handleStderr(e.logger, stderrPr, &wg, send, errCh)
|
||||
|
||||
ps, err := e.processWait()
|
||||
|
||||
// force close streams to close out the stream copying goroutines
|
||||
stdinPr.Close()
|
||||
stdoutPw.Close()
|
||||
stderrPw.Close()
|
||||
|
||||
// wait until we get all process output
|
||||
wg.Wait()
|
||||
|
||||
// wait to flush out output
|
||||
stream.Send(cmdExitResult(ps, err))
|
||||
|
||||
select {
|
||||
case cerr := <-errCh:
|
||||
return cerr
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
func cmdExitResult(ps *os.ProcessState, err error) *drivers.ExecTaskStreamingResponseMsg {
|
||||
exitCode := -1
|
||||
|
||||
if ps == nil {
|
||||
if ee, ok := err.(*exec.ExitError); ok {
|
||||
ps = ee.ProcessState
|
||||
}
|
||||
}
|
||||
|
||||
if ps == nil {
|
||||
exitCode = -2
|
||||
} else if status, ok := ps.Sys().(syscall.WaitStatus); ok {
|
||||
exitCode = status.ExitStatus()
|
||||
if status.Signaled() {
|
||||
const exitSignalBase = 128
|
||||
signal := int(status.Signal())
|
||||
exitCode = exitSignalBase + signal
|
||||
}
|
||||
}
|
||||
|
||||
return &drivers.ExecTaskStreamingResponseMsg{
|
||||
Exited: true,
|
||||
Result: &dproto.ExitResult{
|
||||
ExitCode: int32(exitCode),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func handleStdin(logger hclog.Logger, stdin io.WriteCloser, stream drivers.ExecTaskStream, errCh chan<- error) {
|
||||
for {
|
||||
m, err := stream.Recv()
|
||||
if isClosedError(err) {
|
||||
return
|
||||
} else if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
if m.Stdin != nil {
|
||||
if len(m.Stdin.Data) != 0 {
|
||||
_, err := stdin.Write(m.Stdin.Data)
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
if m.Stdin.Close {
|
||||
stdin.Close()
|
||||
}
|
||||
} else if m.TtySize != nil {
|
||||
err := setTTYSize(stdin, m.TtySize.Height, m.TtySize.Width)
|
||||
if err != nil {
|
||||
errCh <- fmt.Errorf("failed to resize tty: %v", err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// ignore heartbeats
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handleStdout(logger hclog.Logger, reader io.Reader, wg *sync.WaitGroup, send func(*drivers.ExecTaskStreamingResponseMsg) error, errCh chan<- error) {
|
||||
defer wg.Done()
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
// always send output first if we read something
|
||||
if n > 0 {
|
||||
if err := send(&drivers.ExecTaskStreamingResponseMsg{
|
||||
Stdout: &dproto.ExecTaskStreamingIOOperation{
|
||||
Data: buf[:n],
|
||||
},
|
||||
}); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// then process error
|
||||
if isClosedError(err) {
|
||||
if err := send(&drivers.ExecTaskStreamingResponseMsg{
|
||||
Stdout: &dproto.ExecTaskStreamingIOOperation{
|
||||
Close: true,
|
||||
},
|
||||
}); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func handleStderr(logger hclog.Logger, reader io.Reader, wg *sync.WaitGroup, send func(*drivers.ExecTaskStreamingResponseMsg) error, errCh chan<- error) {
|
||||
defer wg.Done()
|
||||
|
||||
buf := make([]byte, 4096)
|
||||
for {
|
||||
n, err := reader.Read(buf)
|
||||
// always send output first if we read something
|
||||
if n > 0 {
|
||||
if err := send(&drivers.ExecTaskStreamingResponseMsg{
|
||||
Stderr: &dproto.ExecTaskStreamingIOOperation{
|
||||
Data: buf[:n],
|
||||
},
|
||||
}); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// then process error
|
||||
if isClosedError(err) {
|
||||
if err := send(&drivers.ExecTaskStreamingResponseMsg{
|
||||
Stderr: &dproto.ExecTaskStreamingIOOperation{
|
||||
Close: true,
|
||||
},
|
||||
}); err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
return
|
||||
} else if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func isClosedError(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return err == io.EOF ||
|
||||
err == io.ErrClosedPipe ||
|
||||
isUnixEIOErr(err)
|
||||
}
|
|
@ -22,6 +22,7 @@ import (
|
|||
"github.com/hashicorp/nomad/client/stats"
|
||||
cstructs "github.com/hashicorp/nomad/client/structs"
|
||||
"github.com/hashicorp/nomad/plugins/drivers"
|
||||
"github.com/kr/pty"
|
||||
|
||||
shelpers "github.com/hashicorp/nomad/helper/stats"
|
||||
)
|
||||
|
@ -77,6 +78,9 @@ type Executor interface {
|
|||
// Exec executes the given command and args inside the executor context
|
||||
// and returns the output and exit code.
|
||||
Exec(deadline time.Time, cmd string, args []string) ([]byte, int, error)
|
||||
|
||||
ExecStreaming(ctx context.Context, cmd []string, tty bool,
|
||||
stream drivers.ExecTaskStream) error
|
||||
}
|
||||
|
||||
// ExecCommand holds the user command, args, and other isolation related
|
||||
|
@ -356,6 +360,53 @@ func ExecScript(ctx context.Context, dir string, env []string, attrs *syscall.Sy
|
|||
return buf.Bytes(), 0, nil
|
||||
}
|
||||
|
||||
func (e *UniversalExecutor) ExecStreaming(ctx context.Context, command []string, tty bool,
|
||||
stream drivers.ExecTaskStream) error {
|
||||
|
||||
if len(command) == 0 {
|
||||
return fmt.Errorf("command is required")
|
||||
}
|
||||
|
||||
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||
|
||||
cmd.Dir = "/"
|
||||
cmd.Env = e.childCmd.Env
|
||||
|
||||
execHelper := &execHelper{
|
||||
logger: e.logger,
|
||||
|
||||
newTerminal: func() (func() (*os.File, error), *os.File, error) {
|
||||
pty, tty, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return func() (*os.File, error) { return pty, nil }, tty, err
|
||||
},
|
||||
setTTY: func(tty *os.File) error {
|
||||
cmd.SysProcAttr = sessionCmdAttr(tty)
|
||||
|
||||
cmd.Stdin = tty
|
||||
cmd.Stdout = tty
|
||||
cmd.Stderr = tty
|
||||
return nil
|
||||
},
|
||||
setIO: func(stdin io.Reader, stdout, stderr io.Writer) error {
|
||||
cmd.Stdin = stdin
|
||||
cmd.Stdout = stdout
|
||||
cmd.Stderr = stderr
|
||||
return nil
|
||||
},
|
||||
processStart: cmd.Start,
|
||||
processWait: func() (*os.ProcessState, error) {
|
||||
err := cmd.Wait()
|
||||
return cmd.ProcessState, err
|
||||
},
|
||||
}
|
||||
|
||||
return execHelper.run(ctx, tty, stream)
|
||||
}
|
||||
|
||||
// Wait waits until a process has exited and returns it's exitcode and errors
|
||||
func (e *UniversalExecutor) Wait(ctx context.Context) (*ProcessState, error) {
|
||||
select {
|
||||
|
|
|
@ -5,6 +5,7 @@ package executor
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
|
@ -28,6 +29,7 @@ import (
|
|||
cgroupFs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||
lconfigs "github.com/opencontainers/runc/libcontainer/configs"
|
||||
ldevices "github.com/opencontainers/runc/libcontainer/devices"
|
||||
lutils "github.com/opencontainers/runc/libcontainer/utils"
|
||||
"github.com/syndtr/gocapability/capability"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
@ -504,6 +506,53 @@ func (l *LibcontainerExecutor) Exec(deadline time.Time, cmd string, args []strin
|
|||
|
||||
}
|
||||
|
||||
func (l *LibcontainerExecutor) newTerminalSocket() (pty func() (*os.File, error), tty *os.File, err error) {
|
||||
parent, child, err := lutils.NewSockPair("socket")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to create terminal: %v", err)
|
||||
}
|
||||
|
||||
return func() (*os.File, error) { return lutils.RecvFd(parent) }, child, err
|
||||
|
||||
}
|
||||
|
||||
func (l *LibcontainerExecutor) ExecStreaming(ctx context.Context, cmd []string, tty bool,
|
||||
stream drivers.ExecTaskStream) error {
|
||||
|
||||
// the task process will be started by the container
|
||||
process := &libcontainer.Process{
|
||||
Args: cmd,
|
||||
Env: l.userProc.Env,
|
||||
User: l.userProc.User,
|
||||
Init: false,
|
||||
Cwd: "/",
|
||||
}
|
||||
|
||||
execHelper := &execHelper{
|
||||
logger: l.logger,
|
||||
|
||||
newTerminal: l.newTerminalSocket,
|
||||
setTTY: func(tty *os.File) error {
|
||||
process.ConsoleSocket = tty
|
||||
return nil
|
||||
},
|
||||
setIO: func(stdin io.Reader, stdout, stderr io.Writer) error {
|
||||
process.Stdin = stdin
|
||||
process.Stdout = stdout
|
||||
process.Stderr = stderr
|
||||
return nil
|
||||
},
|
||||
|
||||
processStart: func() error { return l.container.Run(process) },
|
||||
processWait: func() (*os.ProcessState, error) {
|
||||
return process.Wait()
|
||||
},
|
||||
}
|
||||
|
||||
return execHelper.run(ctx, tty, stream)
|
||||
|
||||
}
|
||||
|
||||
type waitResult struct {
|
||||
ps *os.ProcessState
|
||||
err error
|
||||
|
|
|
@ -47,7 +47,7 @@ func (m *LaunchRequest) Reset() { *m = LaunchRequest{} }
|
|||
func (m *LaunchRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*LaunchRequest) ProtoMessage() {}
|
||||
func (*LaunchRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{0}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{0}
|
||||
}
|
||||
func (m *LaunchRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LaunchRequest.Unmarshal(m, b)
|
||||
|
@ -162,7 +162,7 @@ func (m *LaunchResponse) Reset() { *m = LaunchResponse{} }
|
|||
func (m *LaunchResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*LaunchResponse) ProtoMessage() {}
|
||||
func (*LaunchResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{1}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{1}
|
||||
}
|
||||
func (m *LaunchResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_LaunchResponse.Unmarshal(m, b)
|
||||
|
@ -199,7 +199,7 @@ func (m *WaitRequest) Reset() { *m = WaitRequest{} }
|
|||
func (m *WaitRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*WaitRequest) ProtoMessage() {}
|
||||
func (*WaitRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{2}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{2}
|
||||
}
|
||||
func (m *WaitRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_WaitRequest.Unmarshal(m, b)
|
||||
|
@ -230,7 +230,7 @@ func (m *WaitResponse) Reset() { *m = WaitResponse{} }
|
|||
func (m *WaitResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*WaitResponse) ProtoMessage() {}
|
||||
func (*WaitResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{3}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{3}
|
||||
}
|
||||
func (m *WaitResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_WaitResponse.Unmarshal(m, b)
|
||||
|
@ -269,7 +269,7 @@ func (m *ShutdownRequest) Reset() { *m = ShutdownRequest{} }
|
|||
func (m *ShutdownRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ShutdownRequest) ProtoMessage() {}
|
||||
func (*ShutdownRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{4}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{4}
|
||||
}
|
||||
func (m *ShutdownRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ShutdownRequest.Unmarshal(m, b)
|
||||
|
@ -313,7 +313,7 @@ func (m *ShutdownResponse) Reset() { *m = ShutdownResponse{} }
|
|||
func (m *ShutdownResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ShutdownResponse) ProtoMessage() {}
|
||||
func (*ShutdownResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{5}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{5}
|
||||
}
|
||||
func (m *ShutdownResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ShutdownResponse.Unmarshal(m, b)
|
||||
|
@ -344,7 +344,7 @@ func (m *UpdateResourcesRequest) Reset() { *m = UpdateResourcesRequest{}
|
|||
func (m *UpdateResourcesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateResourcesRequest) ProtoMessage() {}
|
||||
func (*UpdateResourcesRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{6}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{6}
|
||||
}
|
||||
func (m *UpdateResourcesRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_UpdateResourcesRequest.Unmarshal(m, b)
|
||||
|
@ -381,7 +381,7 @@ func (m *UpdateResourcesResponse) Reset() { *m = UpdateResourcesResponse
|
|||
func (m *UpdateResourcesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*UpdateResourcesResponse) ProtoMessage() {}
|
||||
func (*UpdateResourcesResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{7}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{7}
|
||||
}
|
||||
func (m *UpdateResourcesResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_UpdateResourcesResponse.Unmarshal(m, b)
|
||||
|
@ -411,7 +411,7 @@ func (m *VersionRequest) Reset() { *m = VersionRequest{} }
|
|||
func (m *VersionRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*VersionRequest) ProtoMessage() {}
|
||||
func (*VersionRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{8}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{8}
|
||||
}
|
||||
func (m *VersionRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_VersionRequest.Unmarshal(m, b)
|
||||
|
@ -442,7 +442,7 @@ func (m *VersionResponse) Reset() { *m = VersionResponse{} }
|
|||
func (m *VersionResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*VersionResponse) ProtoMessage() {}
|
||||
func (*VersionResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{9}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{9}
|
||||
}
|
||||
func (m *VersionResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_VersionResponse.Unmarshal(m, b)
|
||||
|
@ -480,7 +480,7 @@ func (m *StatsRequest) Reset() { *m = StatsRequest{} }
|
|||
func (m *StatsRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatsRequest) ProtoMessage() {}
|
||||
func (*StatsRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{10}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{10}
|
||||
}
|
||||
func (m *StatsRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatsRequest.Unmarshal(m, b)
|
||||
|
@ -518,7 +518,7 @@ func (m *StatsResponse) Reset() { *m = StatsResponse{} }
|
|||
func (m *StatsResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*StatsResponse) ProtoMessage() {}
|
||||
func (*StatsResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{11}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{11}
|
||||
}
|
||||
func (m *StatsResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_StatsResponse.Unmarshal(m, b)
|
||||
|
@ -556,7 +556,7 @@ func (m *SignalRequest) Reset() { *m = SignalRequest{} }
|
|||
func (m *SignalRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SignalRequest) ProtoMessage() {}
|
||||
func (*SignalRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{12}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{12}
|
||||
}
|
||||
func (m *SignalRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SignalRequest.Unmarshal(m, b)
|
||||
|
@ -593,7 +593,7 @@ func (m *SignalResponse) Reset() { *m = SignalResponse{} }
|
|||
func (m *SignalResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SignalResponse) ProtoMessage() {}
|
||||
func (*SignalResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{13}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{13}
|
||||
}
|
||||
func (m *SignalResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SignalResponse.Unmarshal(m, b)
|
||||
|
@ -626,7 +626,7 @@ func (m *ExecRequest) Reset() { *m = ExecRequest{} }
|
|||
func (m *ExecRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*ExecRequest) ProtoMessage() {}
|
||||
func (*ExecRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{14}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{14}
|
||||
}
|
||||
func (m *ExecRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ExecRequest.Unmarshal(m, b)
|
||||
|
@ -679,7 +679,7 @@ func (m *ExecResponse) Reset() { *m = ExecResponse{} }
|
|||
func (m *ExecResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*ExecResponse) ProtoMessage() {}
|
||||
func (*ExecResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{15}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{15}
|
||||
}
|
||||
func (m *ExecResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ExecResponse.Unmarshal(m, b)
|
||||
|
@ -727,7 +727,7 @@ func (m *ProcessState) Reset() { *m = ProcessState{} }
|
|||
func (m *ProcessState) String() string { return proto.CompactTextString(m) }
|
||||
func (*ProcessState) ProtoMessage() {}
|
||||
func (*ProcessState) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_executor_1eb9aa6040002cd3, []int{16}
|
||||
return fileDescriptor_executor_5ea6ca9df3b0f07e, []int{16}
|
||||
}
|
||||
func (m *ProcessState) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_ProcessState.Unmarshal(m, b)
|
||||
|
@ -815,6 +815,7 @@ type ExecutorClient interface {
|
|||
Stats(ctx context.Context, in *StatsRequest, opts ...grpc.CallOption) (Executor_StatsClient, error)
|
||||
Signal(ctx context.Context, in *SignalRequest, opts ...grpc.CallOption) (*SignalResponse, error)
|
||||
Exec(ctx context.Context, in *ExecRequest, opts ...grpc.CallOption) (*ExecResponse, error)
|
||||
ExecStreaming(ctx context.Context, opts ...grpc.CallOption) (Executor_ExecStreamingClient, error)
|
||||
}
|
||||
|
||||
type executorClient struct {
|
||||
|
@ -920,6 +921,37 @@ func (c *executorClient) Exec(ctx context.Context, in *ExecRequest, opts ...grpc
|
|||
return out, nil
|
||||
}
|
||||
|
||||
func (c *executorClient) ExecStreaming(ctx context.Context, opts ...grpc.CallOption) (Executor_ExecStreamingClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &_Executor_serviceDesc.Streams[1], "/hashicorp.nomad.plugins.executor.proto.Executor/ExecStreaming", opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &executorExecStreamingClient{stream}
|
||||
return x, nil
|
||||
}
|
||||
|
||||
type Executor_ExecStreamingClient interface {
|
||||
Send(*proto1.ExecTaskStreamingRequest) error
|
||||
Recv() (*proto1.ExecTaskStreamingResponse, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type executorExecStreamingClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *executorExecStreamingClient) Send(m *proto1.ExecTaskStreamingRequest) error {
|
||||
return x.ClientStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *executorExecStreamingClient) Recv() (*proto1.ExecTaskStreamingResponse, error) {
|
||||
m := new(proto1.ExecTaskStreamingResponse)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ExecutorServer is the server API for Executor service.
|
||||
type ExecutorServer interface {
|
||||
Launch(context.Context, *LaunchRequest) (*LaunchResponse, error)
|
||||
|
@ -930,6 +962,7 @@ type ExecutorServer interface {
|
|||
Stats(*StatsRequest, Executor_StatsServer) error
|
||||
Signal(context.Context, *SignalRequest) (*SignalResponse, error)
|
||||
Exec(context.Context, *ExecRequest) (*ExecResponse, error)
|
||||
ExecStreaming(Executor_ExecStreamingServer) error
|
||||
}
|
||||
|
||||
func RegisterExecutorServer(s *grpc.Server, srv ExecutorServer) {
|
||||
|
@ -1083,6 +1116,32 @@ func _Executor_Exec_Handler(srv interface{}, ctx context.Context, dec func(inter
|
|||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Executor_ExecStreaming_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
return srv.(ExecutorServer).ExecStreaming(&executorExecStreamingServer{stream})
|
||||
}
|
||||
|
||||
type Executor_ExecStreamingServer interface {
|
||||
Send(*proto1.ExecTaskStreamingResponse) error
|
||||
Recv() (*proto1.ExecTaskStreamingRequest, error)
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type executorExecStreamingServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *executorExecStreamingServer) Send(m *proto1.ExecTaskStreamingResponse) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func (x *executorExecStreamingServer) Recv() (*proto1.ExecTaskStreamingRequest, error) {
|
||||
m := new(proto1.ExecTaskStreamingRequest)
|
||||
if err := x.ServerStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
var _Executor_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "hashicorp.nomad.plugins.executor.proto.Executor",
|
||||
HandlerType: (*ExecutorServer)(nil),
|
||||
|
@ -1122,70 +1181,78 @@ var _Executor_serviceDesc = grpc.ServiceDesc{
|
|||
Handler: _Executor_Stats_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "ExecStreaming",
|
||||
Handler: _Executor_ExecStreaming_Handler,
|
||||
ServerStreams: true,
|
||||
ClientStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "drivers/shared/executor/proto/executor.proto",
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterFile("drivers/shared/executor/proto/executor.proto", fileDescriptor_executor_1eb9aa6040002cd3)
|
||||
proto.RegisterFile("drivers/shared/executor/proto/executor.proto", fileDescriptor_executor_5ea6ca9df3b0f07e)
|
||||
}
|
||||
|
||||
var fileDescriptor_executor_1eb9aa6040002cd3 = []byte{
|
||||
// 885 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x4b, 0x6f, 0xe4, 0x44,
|
||||
0x10, 0x5e, 0xc7, 0x99, 0x57, 0xcd, 0xe4, 0xa1, 0x16, 0x0a, 0x5e, 0x73, 0xd8, 0xc1, 0x07, 0x76,
|
||||
0x04, 0x8b, 0x27, 0xca, 0xbe, 0xb8, 0x00, 0x12, 0xc9, 0xc2, 0x25, 0xac, 0x22, 0x67, 0x61, 0x25,
|
||||
0x0e, 0x0c, 0x1d, 0xbb, 0xb1, 0x5b, 0x99, 0x71, 0x9b, 0xee, 0xf6, 0x30, 0x48, 0x48, 0x9c, 0xf8,
|
||||
0x07, 0xfc, 0x52, 0x8e, 0x9c, 0x50, 0xbf, 0x9c, 0x99, 0xec, 0x12, 0x79, 0x40, 0x9c, 0xa6, 0xab,
|
||||
0x5c, 0xdf, 0x57, 0x55, 0xdd, 0x55, 0xdf, 0xc0, 0xa3, 0x8c, 0xd3, 0x25, 0xe1, 0x62, 0x2a, 0x0a,
|
||||
0xcc, 0x49, 0x36, 0x25, 0x2b, 0x92, 0xd6, 0x92, 0xf1, 0x69, 0xc5, 0x99, 0x64, 0x8d, 0x19, 0x6b,
|
||||
0x13, 0x7d, 0x50, 0x60, 0x51, 0xd0, 0x94, 0xf1, 0x2a, 0x2e, 0xd9, 0x02, 0x67, 0x71, 0x35, 0xaf,
|
||||
0x73, 0x5a, 0x8a, 0x78, 0x33, 0x2e, 0x7c, 0x90, 0x33, 0x96, 0xcf, 0x89, 0x21, 0xb9, 0xaa, 0x7f,
|
||||
0x9c, 0x4a, 0xba, 0x20, 0x42, 0xe2, 0x45, 0x65, 0x03, 0x3e, 0xcd, 0xa9, 0x2c, 0xea, 0xab, 0x38,
|
||||
0x65, 0x8b, 0x69, 0xc3, 0x39, 0xd5, 0x9c, 0x53, 0xcb, 0x39, 0x75, 0x95, 0x99, 0x4a, 0x8c, 0x65,
|
||||
0xe0, 0xd1, 0x9f, 0x3e, 0xec, 0x9d, 0xe3, 0xba, 0x4c, 0x8b, 0x84, 0xfc, 0x54, 0x13, 0x21, 0xd1,
|
||||
0x21, 0xf8, 0xe9, 0x22, 0x0b, 0xbc, 0xb1, 0x37, 0x19, 0x24, 0xea, 0x88, 0x10, 0xec, 0x62, 0x9e,
|
||||
0x8b, 0x60, 0x67, 0xec, 0x4f, 0x06, 0x89, 0x3e, 0xa3, 0x97, 0x30, 0xe0, 0x44, 0xb0, 0x9a, 0xa7,
|
||||
0x44, 0x04, 0xfe, 0xd8, 0x9b, 0x0c, 0x4f, 0x8e, 0xe3, 0x7f, 0xea, 0xc9, 0xe6, 0x37, 0x29, 0xe3,
|
||||
0xc4, 0xe1, 0x92, 0x1b, 0x0a, 0xf4, 0x00, 0x86, 0x42, 0x66, 0xac, 0x96, 0xb3, 0x0a, 0xcb, 0x22,
|
||||
0xd8, 0xd5, 0xd9, 0xc1, 0xb8, 0x2e, 0xb0, 0x2c, 0x6c, 0x00, 0xe1, 0xdc, 0x04, 0x74, 0x9a, 0x00,
|
||||
0xc2, 0xb9, 0x0e, 0x38, 0x04, 0x9f, 0x94, 0xcb, 0xa0, 0xab, 0x8b, 0x54, 0x47, 0x55, 0x77, 0x2d,
|
||||
0x08, 0x0f, 0x7a, 0x3a, 0x56, 0x9f, 0xd1, 0x7d, 0xe8, 0x4b, 0x2c, 0xae, 0x67, 0x19, 0xe5, 0x41,
|
||||
0x5f, 0xfb, 0x7b, 0xca, 0x3e, 0xa3, 0x1c, 0x3d, 0x84, 0x03, 0x57, 0xcf, 0x6c, 0x4e, 0x17, 0x54,
|
||||
0x8a, 0x60, 0x30, 0xf6, 0x26, 0xfd, 0x64, 0xdf, 0xb9, 0xcf, 0xb5, 0x17, 0x1d, 0xc3, 0x3b, 0x57,
|
||||
0x58, 0xd0, 0x74, 0x56, 0x71, 0x96, 0x12, 0x21, 0x66, 0x69, 0xce, 0x59, 0x5d, 0x05, 0xa0, 0xa3,
|
||||
0x91, 0xfe, 0x76, 0x61, 0x3e, 0x9d, 0xea, 0x2f, 0xe8, 0x0c, 0xba, 0x0b, 0x56, 0x97, 0x52, 0x04,
|
||||
0xc3, 0xb1, 0x3f, 0x19, 0x9e, 0x3c, 0x6a, 0x79, 0x55, 0x5f, 0x2b, 0x50, 0x62, 0xb1, 0xe8, 0x2b,
|
||||
0xe8, 0x65, 0x64, 0x49, 0xd5, 0x8d, 0x8f, 0x34, 0xcd, 0xc7, 0x2d, 0x69, 0xce, 0x34, 0x2a, 0x71,
|
||||
0xe8, 0xe8, 0x07, 0xd8, 0x77, 0x6f, 0x2e, 0x2a, 0x56, 0x0a, 0x82, 0x5e, 0x42, 0xcf, 0x36, 0xa3,
|
||||
0x1f, 0x7e, 0x78, 0xf2, 0x24, 0x6e, 0x37, 0xa0, 0xb1, 0x6d, 0xf4, 0x52, 0x62, 0x49, 0x12, 0x47,
|
||||
0x12, 0xed, 0xc1, 0xf0, 0x35, 0xa6, 0xd2, 0xce, 0x54, 0xf4, 0x3d, 0x8c, 0x8c, 0xf9, 0x3f, 0xa5,
|
||||
0x3b, 0x87, 0x83, 0xcb, 0xa2, 0x96, 0x19, 0xfb, 0xb9, 0x74, 0x63, 0x7c, 0x04, 0x5d, 0x41, 0xf3,
|
||||
0x12, 0xcf, 0xed, 0x24, 0x5b, 0x0b, 0xbd, 0x0f, 0xa3, 0x9c, 0xe3, 0x94, 0xcc, 0x2a, 0xc2, 0x29,
|
||||
0xcb, 0x82, 0x9d, 0xb1, 0x37, 0xf1, 0x93, 0xa1, 0xf6, 0x5d, 0x68, 0x57, 0x84, 0xe0, 0xf0, 0x86,
|
||||
0xcd, 0x54, 0x1c, 0x15, 0x70, 0xf4, 0x4d, 0x95, 0xa9, 0xa4, 0xcd, 0xf4, 0xda, 0x44, 0x1b, 0x9b,
|
||||
0xe0, 0xfd, 0xe7, 0x4d, 0x88, 0xee, 0xc3, 0xbb, 0x6f, 0x64, 0xb2, 0x45, 0x1c, 0xc2, 0xfe, 0xb7,
|
||||
0x84, 0x0b, 0xca, 0x5c, 0x97, 0xd1, 0x47, 0x70, 0xd0, 0x78, 0xec, 0xdd, 0x06, 0xd0, 0x5b, 0x1a,
|
||||
0x97, 0xed, 0xdc, 0x99, 0xd1, 0x87, 0x30, 0x52, 0xf7, 0xd6, 0x54, 0x1e, 0x42, 0x9f, 0x96, 0x92,
|
||||
0xf0, 0xa5, 0xbd, 0x24, 0x3f, 0x69, 0xec, 0xe8, 0x35, 0xec, 0xd9, 0x58, 0x4b, 0xfb, 0x25, 0x74,
|
||||
0x84, 0x72, 0x6c, 0xd9, 0xe2, 0x2b, 0x2c, 0xae, 0x0d, 0x91, 0x81, 0x47, 0x0f, 0x61, 0xef, 0x52,
|
||||
0xbf, 0xc4, 0xdb, 0x1f, 0xaa, 0xe3, 0x1e, 0x4a, 0x35, 0xeb, 0x02, 0x6d, 0xfb, 0xd7, 0x30, 0x7c,
|
||||
0xb1, 0x22, 0xa9, 0x03, 0x3e, 0x83, 0x7e, 0x46, 0x70, 0x36, 0xa7, 0x25, 0xb1, 0x45, 0x85, 0xb1,
|
||||
0x51, 0xcb, 0xd8, 0xa9, 0x65, 0xfc, 0xca, 0xa9, 0x65, 0xd2, 0xc4, 0x3a, 0x81, 0xdb, 0x79, 0x53,
|
||||
0xe0, 0xfc, 0x1b, 0x81, 0x8b, 0x4e, 0x61, 0x64, 0x92, 0xd9, 0xfe, 0x8f, 0xa0, 0xcb, 0x6a, 0x59,
|
||||
0xd5, 0x52, 0xe7, 0x1a, 0x25, 0xd6, 0x42, 0xef, 0xc1, 0x80, 0xac, 0xa8, 0x9c, 0xa5, 0x2c, 0x23,
|
||||
0x9a, 0xb3, 0x93, 0xf4, 0x95, 0xe3, 0x94, 0x65, 0x24, 0xfa, 0xdd, 0x83, 0xd1, 0xfa, 0xc4, 0xaa,
|
||||
0xdc, 0x15, 0xcd, 0x6c, 0xa7, 0xea, 0x78, 0x27, 0x7e, 0xed, 0x6e, 0xfc, 0xf5, 0xbb, 0x41, 0x31,
|
||||
0xec, 0xaa, 0xff, 0x01, 0x2d, 0x93, 0x77, 0xb7, 0xad, 0xe3, 0x4e, 0xfe, 0xea, 0x41, 0xff, 0x85,
|
||||
0x5d, 0x24, 0xf4, 0x0b, 0x74, 0xcd, 0xf6, 0xa3, 0xa7, 0x6d, 0xb7, 0x6e, 0xe3, 0x1f, 0x22, 0x7c,
|
||||
0xb6, 0x2d, 0xcc, 0xbe, 0xdf, 0x3d, 0x24, 0x60, 0x57, 0xe9, 0x00, 0x7a, 0xdc, 0x96, 0x61, 0x4d,
|
||||
0x44, 0xc2, 0x27, 0xdb, 0x81, 0x9a, 0xa4, 0xbf, 0x41, 0xdf, 0xad, 0x33, 0x7a, 0xde, 0x96, 0xe3,
|
||||
0x96, 0x9c, 0x84, 0x9f, 0x6c, 0x0f, 0x6c, 0x0a, 0xf8, 0xc3, 0x83, 0x83, 0x5b, 0x2b, 0x8d, 0x3e,
|
||||
0x6b, 0xcb, 0xf7, 0x76, 0xd5, 0x09, 0x3f, 0xff, 0xd7, 0xf8, 0xa6, 0xac, 0x5f, 0xa1, 0x67, 0xb5,
|
||||
0x03, 0xb5, 0x7e, 0xd1, 0x4d, 0xf9, 0x09, 0x9f, 0x6f, 0x8d, 0x6b, 0xb2, 0xaf, 0xa0, 0xa3, 0x75,
|
||||
0x01, 0xb5, 0x7e, 0xd6, 0x75, 0xed, 0x0a, 0x9f, 0x6e, 0x89, 0x72, 0x79, 0x8f, 0x3d, 0x35, 0xff,
|
||||
0x46, 0x58, 0xda, 0xcf, 0xff, 0x86, 0x62, 0xb5, 0x9f, 0xff, 0x5b, 0xfa, 0xa5, 0xe7, 0x5f, 0xad,
|
||||
0x61, 0xfb, 0xf9, 0x5f, 0xd3, 0xbb, 0xf6, 0xf3, 0xbf, 0xae, 0x5b, 0xd1, 0xbd, 0x2f, 0x7a, 0xdf,
|
||||
0x75, 0x8c, 0x30, 0x74, 0xf5, 0xcf, 0xe3, 0xbf, 0x03, 0x00, 0x00, 0xff, 0xff, 0x2f, 0x08, 0xfe,
|
||||
0x1f, 0xaa, 0x0a, 0x00, 0x00,
|
||||
var fileDescriptor_executor_5ea6ca9df3b0f07e = []byte{
|
||||
// 919 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x5f, 0x6f, 0xdc, 0x44,
|
||||
0x10, 0xaf, 0xeb, 0xdc, 0xbf, 0xb9, 0xbb, 0x24, 0x5a, 0xa1, 0xe0, 0x9a, 0x87, 0x1e, 0x7e, 0xa0,
|
||||
0x27, 0x28, 0xbe, 0x28, 0xfd, 0xc7, 0x0b, 0x14, 0x91, 0x14, 0x5e, 0x42, 0x15, 0x39, 0x85, 0x4a,
|
||||
0x3c, 0x70, 0x6c, 0xec, 0xc5, 0x5e, 0xe5, 0xce, 0x6b, 0x76, 0xd7, 0x47, 0x90, 0x90, 0x78, 0xe2,
|
||||
0x1b, 0x80, 0xc4, 0xe7, 0xe4, 0x13, 0xa0, 0xfd, 0xe7, 0xdc, 0xa5, 0xa5, 0xf2, 0x15, 0xf1, 0x74,
|
||||
0x3b, 0xe3, 0xf9, 0xfd, 0x66, 0x66, 0x77, 0xe6, 0x77, 0x70, 0x3f, 0xe3, 0x74, 0x45, 0xb8, 0x98,
|
||||
0x89, 0x02, 0x73, 0x92, 0xcd, 0xc8, 0x15, 0x49, 0x6b, 0xc9, 0xf8, 0xac, 0xe2, 0x4c, 0xb2, 0xc6,
|
||||
0x8c, 0xb5, 0x89, 0x3e, 0x28, 0xb0, 0x28, 0x68, 0xca, 0x78, 0x15, 0x97, 0x6c, 0x89, 0xb3, 0xb8,
|
||||
0x5a, 0xd4, 0x39, 0x2d, 0x45, 0xbc, 0x19, 0x17, 0xde, 0xcd, 0x19, 0xcb, 0x17, 0xc4, 0x90, 0x5c,
|
||||
0xd4, 0x3f, 0xce, 0x24, 0x5d, 0x12, 0x21, 0xf1, 0xb2, 0xb2, 0x01, 0x9f, 0xe6, 0x54, 0x16, 0xf5,
|
||||
0x45, 0x9c, 0xb2, 0xe5, 0xac, 0xe1, 0x9c, 0x69, 0xce, 0x99, 0xe5, 0x9c, 0xb9, 0xca, 0x4c, 0x25,
|
||||
0xc6, 0x32, 0xf0, 0xe8, 0x6f, 0x1f, 0xc6, 0xa7, 0xb8, 0x2e, 0xd3, 0x22, 0x21, 0x3f, 0xd5, 0x44,
|
||||
0x48, 0xb4, 0x0f, 0x7e, 0xba, 0xcc, 0x02, 0x6f, 0xe2, 0x4d, 0x07, 0x89, 0x3a, 0x22, 0x04, 0x3b,
|
||||
0x98, 0xe7, 0x22, 0xb8, 0x3d, 0xf1, 0xa7, 0x83, 0x44, 0x9f, 0xd1, 0x73, 0x18, 0x70, 0x22, 0x58,
|
||||
0xcd, 0x53, 0x22, 0x02, 0x7f, 0xe2, 0x4d, 0x87, 0x47, 0x87, 0xf1, 0xbf, 0xf5, 0x64, 0xf3, 0x9b,
|
||||
0x94, 0x71, 0xe2, 0x70, 0xc9, 0x35, 0x05, 0xba, 0x0b, 0x43, 0x21, 0x33, 0x56, 0xcb, 0x79, 0x85,
|
||||
0x65, 0x11, 0xec, 0xe8, 0xec, 0x60, 0x5c, 0x67, 0x58, 0x16, 0x36, 0x80, 0x70, 0x6e, 0x02, 0x3a,
|
||||
0x4d, 0x00, 0xe1, 0x5c, 0x07, 0xec, 0x83, 0x4f, 0xca, 0x55, 0xd0, 0xd5, 0x45, 0xaa, 0xa3, 0xaa,
|
||||
0xbb, 0x16, 0x84, 0x07, 0x3d, 0x1d, 0xab, 0xcf, 0xe8, 0x0e, 0xf4, 0x25, 0x16, 0x97, 0xf3, 0x8c,
|
||||
0xf2, 0xa0, 0xaf, 0xfd, 0x3d, 0x65, 0x9f, 0x50, 0x8e, 0xee, 0xc1, 0x9e, 0xab, 0x67, 0xbe, 0xa0,
|
||||
0x4b, 0x2a, 0x45, 0x30, 0x98, 0x78, 0xd3, 0x7e, 0xb2, 0xeb, 0xdc, 0xa7, 0xda, 0x8b, 0x0e, 0xe1,
|
||||
0x9d, 0x0b, 0x2c, 0x68, 0x3a, 0xaf, 0x38, 0x4b, 0x89, 0x10, 0xf3, 0x34, 0xe7, 0xac, 0xae, 0x02,
|
||||
0xd0, 0xd1, 0x48, 0x7f, 0x3b, 0x33, 0x9f, 0x8e, 0xf5, 0x17, 0x74, 0x02, 0xdd, 0x25, 0xab, 0x4b,
|
||||
0x29, 0x82, 0xe1, 0xc4, 0x9f, 0x0e, 0x8f, 0xee, 0xb7, 0xbc, 0xaa, 0xaf, 0x15, 0x28, 0xb1, 0x58,
|
||||
0xf4, 0x15, 0xf4, 0x32, 0xb2, 0xa2, 0xea, 0xc6, 0x47, 0x9a, 0xe6, 0xe3, 0x96, 0x34, 0x27, 0x1a,
|
||||
0x95, 0x38, 0x74, 0xf4, 0x03, 0xec, 0xba, 0x37, 0x17, 0x15, 0x2b, 0x05, 0x41, 0xcf, 0xa1, 0x67,
|
||||
0x9b, 0xd1, 0x0f, 0x3f, 0x3c, 0x7a, 0x18, 0xb7, 0x1b, 0xd0, 0xd8, 0x36, 0x7a, 0x2e, 0xb1, 0x24,
|
||||
0x89, 0x23, 0x89, 0xc6, 0x30, 0x7c, 0x89, 0xa9, 0xb4, 0x33, 0x15, 0x7d, 0x0f, 0x23, 0x63, 0xfe,
|
||||
0x4f, 0xe9, 0x4e, 0x61, 0xef, 0xbc, 0xa8, 0x65, 0xc6, 0x7e, 0x2e, 0xdd, 0x18, 0x1f, 0x40, 0x57,
|
||||
0xd0, 0xbc, 0xc4, 0x0b, 0x3b, 0xc9, 0xd6, 0x42, 0xef, 0xc3, 0x28, 0xe7, 0x38, 0x25, 0xf3, 0x8a,
|
||||
0x70, 0xca, 0xb2, 0xe0, 0xf6, 0xc4, 0x9b, 0xfa, 0xc9, 0x50, 0xfb, 0xce, 0xb4, 0x2b, 0x42, 0xb0,
|
||||
0x7f, 0xcd, 0x66, 0x2a, 0x8e, 0x0a, 0x38, 0xf8, 0xa6, 0xca, 0x54, 0xd2, 0x66, 0x7a, 0x6d, 0xa2,
|
||||
0x8d, 0x4d, 0xf0, 0xfe, 0xf3, 0x26, 0x44, 0x77, 0xe0, 0xdd, 0x57, 0x32, 0xd9, 0x22, 0xf6, 0x61,
|
||||
0xf7, 0x5b, 0xc2, 0x05, 0x65, 0xae, 0xcb, 0xe8, 0x23, 0xd8, 0x6b, 0x3c, 0xf6, 0x6e, 0x03, 0xe8,
|
||||
0xad, 0x8c, 0xcb, 0x76, 0xee, 0xcc, 0xe8, 0x43, 0x18, 0xa9, 0x7b, 0x6b, 0x2a, 0x0f, 0xa1, 0x4f,
|
||||
0x4b, 0x49, 0xf8, 0xca, 0x5e, 0x92, 0x9f, 0x34, 0x76, 0xf4, 0x12, 0xc6, 0x36, 0xd6, 0xd2, 0x7e,
|
||||
0x09, 0x1d, 0xa1, 0x1c, 0x5b, 0xb6, 0xf8, 0x02, 0x8b, 0x4b, 0x43, 0x64, 0xe0, 0xd1, 0x3d, 0x18,
|
||||
0x9f, 0xeb, 0x97, 0x78, 0xfd, 0x43, 0x75, 0xdc, 0x43, 0xa9, 0x66, 0x5d, 0xa0, 0x6d, 0xff, 0x12,
|
||||
0x86, 0xcf, 0xae, 0x48, 0xea, 0x80, 0x8f, 0xa1, 0x9f, 0x11, 0x9c, 0x2d, 0x68, 0x49, 0x6c, 0x51,
|
||||
0x61, 0x6c, 0xd4, 0x32, 0x76, 0x6a, 0x19, 0xbf, 0x70, 0x6a, 0x99, 0x34, 0xb1, 0x4e, 0xe0, 0x6e,
|
||||
0xbf, 0x2a, 0x70, 0xfe, 0xb5, 0xc0, 0x45, 0xc7, 0x30, 0x32, 0xc9, 0x6c, 0xff, 0x07, 0xd0, 0x65,
|
||||
0xb5, 0xac, 0x6a, 0xa9, 0x73, 0x8d, 0x12, 0x6b, 0xa1, 0xf7, 0x60, 0x40, 0xae, 0xa8, 0x9c, 0xa7,
|
||||
0x2c, 0x23, 0x9a, 0xb3, 0x93, 0xf4, 0x95, 0xe3, 0x98, 0x65, 0x24, 0xfa, 0xdd, 0x83, 0xd1, 0xfa,
|
||||
0xc4, 0xaa, 0xdc, 0x15, 0xcd, 0x6c, 0xa7, 0xea, 0xf8, 0x46, 0xfc, 0xda, 0xdd, 0xf8, 0xeb, 0x77,
|
||||
0x83, 0x62, 0xd8, 0x51, 0xff, 0x03, 0x5a, 0x26, 0xdf, 0xdc, 0xb6, 0x8e, 0x3b, 0xfa, 0x73, 0x00,
|
||||
0xfd, 0x67, 0x76, 0x91, 0xd0, 0x2f, 0xd0, 0x35, 0xdb, 0x8f, 0x1e, 0xb5, 0xdd, 0xba, 0x8d, 0x7f,
|
||||
0x88, 0xf0, 0xf1, 0xb6, 0x30, 0xfb, 0x7e, 0xb7, 0x90, 0x80, 0x1d, 0xa5, 0x03, 0xe8, 0x41, 0x5b,
|
||||
0x86, 0x35, 0x11, 0x09, 0x1f, 0x6e, 0x07, 0x6a, 0x92, 0xfe, 0x06, 0x7d, 0xb7, 0xce, 0xe8, 0x49,
|
||||
0x5b, 0x8e, 0x1b, 0x72, 0x12, 0x7e, 0xb2, 0x3d, 0xb0, 0x29, 0xe0, 0x0f, 0x0f, 0xf6, 0x6e, 0xac,
|
||||
0x34, 0xfa, 0xac, 0x2d, 0xdf, 0xeb, 0x55, 0x27, 0x7c, 0xfa, 0xd6, 0xf8, 0xa6, 0xac, 0x5f, 0xa1,
|
||||
0x67, 0xb5, 0x03, 0xb5, 0x7e, 0xd1, 0x4d, 0xf9, 0x09, 0x9f, 0x6c, 0x8d, 0x6b, 0xb2, 0x5f, 0x41,
|
||||
0x47, 0xeb, 0x02, 0x6a, 0xfd, 0xac, 0xeb, 0xda, 0x15, 0x3e, 0xda, 0x12, 0xe5, 0xf2, 0x1e, 0x7a,
|
||||
0x6a, 0xfe, 0x8d, 0xb0, 0xb4, 0x9f, 0xff, 0x0d, 0xc5, 0x6a, 0x3f, 0xff, 0x37, 0xf4, 0x4b, 0xcf,
|
||||
0xbf, 0x5a, 0xc3, 0xf6, 0xf3, 0xbf, 0xa6, 0x77, 0xed, 0xe7, 0x7f, 0x5d, 0xb7, 0xa2, 0x5b, 0xe8,
|
||||
0x2f, 0x0f, 0xc6, 0xca, 0x75, 0x2e, 0x39, 0xc1, 0x4b, 0x5a, 0xe6, 0xe8, 0x69, 0x4b, 0xf1, 0x56,
|
||||
0x28, 0x23, 0xe0, 0x16, 0xe9, 0x4a, 0xf9, 0xfc, 0xed, 0x09, 0x5c, 0x59, 0x53, 0xef, 0xd0, 0xfb,
|
||||
0xa2, 0xf7, 0x5d, 0xc7, 0x68, 0x56, 0x57, 0xff, 0x3c, 0xf8, 0x27, 0x00, 0x00, 0xff, 0xff, 0xe4,
|
||||
0x09, 0xe7, 0x2c, 0x45, 0x0b, 0x00, 0x00,
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ service Executor {
|
|||
rpc Stats(StatsRequest) returns (stream StatsResponse) {}
|
||||
rpc Signal(SignalRequest) returns (SignalResponse) {}
|
||||
rpc Exec(ExecRequest) returns (ExecResponse) {}
|
||||
rpc ExecStreaming(stream hashicorp.nomad.plugins.drivers.proto.ExecTaskStreamingRequest) returns (stream hashicorp.nomad.plugins.drivers.proto.ExecTaskStreamingResponse) {}
|
||||
}
|
||||
|
||||
message LaunchRequest {
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/kr/pty"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
func sessionCmdAttr(tty *os.File) *syscall.SysProcAttr {
|
||||
return &syscall.SysProcAttr{
|
||||
Setsid: true,
|
||||
Setctty: true,
|
||||
Ctty: int(tty.Fd()),
|
||||
}
|
||||
}
|
||||
|
||||
func setTTYSize(w io.Writer, height, width int32) error {
|
||||
f, ok := w.(*os.File)
|
||||
if !ok {
|
||||
return fmt.Errorf("attempted to resize a non-tty session")
|
||||
}
|
||||
|
||||
return pty.Setsize(f, &pty.Winsize{
|
||||
Rows: uint16(height),
|
||||
Cols: uint16(width),
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func isUnixEIOErr(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.Contains(err.Error(), unix.EIO.Error())
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
// +build windows
|
||||
|
||||
package executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func sessionCmdAttr(tty *os.File) *syscall.SysProcAttr {
|
||||
return &syscall.SysProcAttr{}
|
||||
}
|
||||
|
||||
func setTTYSize(w io.Writer, height, width int32) error {
|
||||
return fmt.Errorf("unsupported")
|
||||
|
||||
}
|
||||
|
||||
func isUnixEIOErr(err error) bool {
|
||||
return false
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package executor
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
|
@ -154,3 +155,18 @@ func (s *grpcExecutorServer) Exec(ctx context.Context, req *proto.ExecRequest) (
|
|||
ExitCode: int32(exit),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *grpcExecutorServer) ExecStreaming(server proto.Executor_ExecStreamingServer) error {
|
||||
msg, err := server.Recv()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to receive initial message: %v", err)
|
||||
}
|
||||
|
||||
if msg.Setup == nil {
|
||||
return fmt.Errorf("first message should always be setup")
|
||||
}
|
||||
|
||||
return s.impl.ExecStreaming(server.Context(),
|
||||
msg.Setup.Command, msg.Setup.Tty,
|
||||
server)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2011 Keith Rarick
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute,
|
||||
sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall
|
||||
be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
||||
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
|
||||
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,100 @@
|
|||
# pty
|
||||
|
||||
Pty is a Go package for using unix pseudo-terminals.
|
||||
|
||||
## Install
|
||||
|
||||
go get github.com/kr/pty
|
||||
|
||||
## Example
|
||||
|
||||
### Command
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/kr/pty"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c := exec.Command("grep", "--color=auto", "bar")
|
||||
f, err := pty.Start(c)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
go func() {
|
||||
f.Write([]byte("foo\n"))
|
||||
f.Write([]byte("bar\n"))
|
||||
f.Write([]byte("baz\n"))
|
||||
f.Write([]byte{4}) // EOT
|
||||
}()
|
||||
io.Copy(os.Stdout, f)
|
||||
}
|
||||
```
|
||||
|
||||
### Shell
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"github.com/kr/pty"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
)
|
||||
|
||||
func test() error {
|
||||
// Create arbitrary command.
|
||||
c := exec.Command("bash")
|
||||
|
||||
// Start the command with a pty.
|
||||
ptmx, err := pty.Start(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Make sure to close the pty at the end.
|
||||
defer func() { _ = ptmx.Close() }() // Best effort.
|
||||
|
||||
// Handle pty size.
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGWINCH)
|
||||
go func() {
|
||||
for range ch {
|
||||
if err := pty.InheritSize(os.Stdin, ptmx); err != nil {
|
||||
log.Printf("error resizing pty: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
ch <- syscall.SIGWINCH // Initial resize.
|
||||
|
||||
// Set stdin in raw mode.
|
||||
oldState, err := terminal.MakeRaw(int(os.Stdin.Fd()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer func() { _ = terminal.Restore(int(os.Stdin.Fd()), oldState) }() // Best effort.
|
||||
|
||||
// Copy stdin to the pty and the pty to stdout.
|
||||
go func() { _, _ = io.Copy(ptmx, os.Stdin) }()
|
||||
_, _ = io.Copy(os.Stdout, ptmx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := test(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
```
|
|
@ -0,0 +1,16 @@
|
|||
// Package pty provides functions for working with Unix terminals.
|
||||
package pty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
)
|
||||
|
||||
// ErrUnsupported is returned if a function is not
|
||||
// available on the current platform.
|
||||
var ErrUnsupported = errors.New("unsupported")
|
||||
|
||||
// Opens a pty and its corresponding tty.
|
||||
func Open() (pty, tty *os.File, err error) {
|
||||
return open()
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module github.com/kr/pty
|
||||
|
||||
go 1.12
|
|
@ -0,0 +1,13 @@
|
|||
// +build !windows
|
||||
|
||||
package pty
|
||||
|
||||
import "syscall"
|
||||
|
||||
func ioctl(fd, cmd, ptr uintptr) error {
|
||||
_, _, e := syscall.Syscall(syscall.SYS_IOCTL, fd, cmd, ptr)
|
||||
if e != 0 {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
// +build darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package pty
|
||||
|
||||
// from <sys/ioccom.h>
|
||||
const (
|
||||
_IOC_VOID uintptr = 0x20000000
|
||||
_IOC_OUT uintptr = 0x40000000
|
||||
_IOC_IN uintptr = 0x80000000
|
||||
_IOC_IN_OUT uintptr = _IOC_OUT | _IOC_IN
|
||||
_IOC_DIRMASK = _IOC_VOID | _IOC_OUT | _IOC_IN
|
||||
|
||||
_IOC_PARAM_SHIFT = 13
|
||||
_IOC_PARAM_MASK = (1 << _IOC_PARAM_SHIFT) - 1
|
||||
)
|
||||
|
||||
func _IOC_PARM_LEN(ioctl uintptr) uintptr {
|
||||
return (ioctl >> 16) & _IOC_PARAM_MASK
|
||||
}
|
||||
|
||||
func _IOC(inout uintptr, group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
||||
return inout | (param_len&_IOC_PARAM_MASK)<<16 | uintptr(group)<<8 | ioctl_num
|
||||
}
|
||||
|
||||
func _IO(group byte, ioctl_num uintptr) uintptr {
|
||||
return _IOC(_IOC_VOID, group, ioctl_num, 0)
|
||||
}
|
||||
|
||||
func _IOR(group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
||||
return _IOC(_IOC_OUT, group, ioctl_num, param_len)
|
||||
}
|
||||
|
||||
func _IOW(group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
||||
return _IOC(_IOC_IN, group, ioctl_num, param_len)
|
||||
}
|
||||
|
||||
func _IOWR(group byte, ioctl_num uintptr, param_len uintptr) uintptr {
|
||||
return _IOC(_IOC_IN_OUT, group, ioctl_num, param_len)
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
GOOSARCH="${GOOS}_${GOARCH}"
|
||||
case "$GOOSARCH" in
|
||||
_* | *_ | _)
|
||||
echo 'undefined $GOOS_$GOARCH:' "$GOOSARCH" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
GODEFS="go tool cgo -godefs"
|
||||
|
||||
$GODEFS types.go |gofmt > ztypes_$GOARCH.go
|
||||
|
||||
case $GOOS in
|
||||
freebsd|dragonfly|openbsd)
|
||||
$GODEFS types_$GOOS.go |gofmt > ztypes_$GOOSARCH.go
|
||||
;;
|
||||
esac
|
|
@ -0,0 +1,65 @@
|
|||
package pty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
pFD, err := syscall.Open("/dev/ptmx", syscall.O_RDWR|syscall.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p := os.NewFile(uintptr(pFD), "/dev/ptmx")
|
||||
// In case of error after this point, make sure we close the ptmx fd.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = p.Close() // Best effort.
|
||||
}
|
||||
}()
|
||||
|
||||
sname, err := ptsname(p)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := grantpt(p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := unlockpt(p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t, err := os.OpenFile(sname, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return p, t, nil
|
||||
}
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
n := make([]byte, _IOC_PARM_LEN(syscall.TIOCPTYGNAME))
|
||||
|
||||
err := ioctl(f.Fd(), syscall.TIOCPTYGNAME, uintptr(unsafe.Pointer(&n[0])))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i, c := range n {
|
||||
if c == 0 {
|
||||
return string(n[:i]), nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("TIOCPTYGNAME string not NUL-terminated")
|
||||
}
|
||||
|
||||
func grantpt(f *os.File) error {
|
||||
return ioctl(f.Fd(), syscall.TIOCPTYGRANT, 0)
|
||||
}
|
||||
|
||||
func unlockpt(f *os.File) error {
|
||||
return ioctl(f.Fd(), syscall.TIOCPTYUNLK, 0)
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package pty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// same code as pty_darwin.go
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// In case of error after this point, make sure we close the ptmx fd.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = p.Close() // Best effort.
|
||||
}
|
||||
}()
|
||||
|
||||
sname, err := ptsname(p)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := grantpt(p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := unlockpt(p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t, err := os.OpenFile(sname, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return p, t, nil
|
||||
}
|
||||
|
||||
func grantpt(f *os.File) error {
|
||||
_, err := isptmaster(f.Fd())
|
||||
return err
|
||||
}
|
||||
|
||||
func unlockpt(f *os.File) error {
|
||||
_, err := isptmaster(f.Fd())
|
||||
return err
|
||||
}
|
||||
|
||||
func isptmaster(fd uintptr) (bool, error) {
|
||||
err := ioctl(fd, syscall.TIOCISPTMASTER, 0)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
emptyFiodgnameArg fiodgnameArg
|
||||
ioctl_FIODNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
|
||||
)
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
name := make([]byte, _C_SPECNAMELEN)
|
||||
fa := fiodgnameArg{Name: (*byte)(unsafe.Pointer(&name[0])), Len: _C_SPECNAMELEN, Pad_cgo_0: [4]byte{0, 0, 0, 0}}
|
||||
|
||||
err := ioctl(f.Fd(), ioctl_FIODNAME, uintptr(unsafe.Pointer(&fa)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i, c := range name {
|
||||
if c == 0 {
|
||||
s := "/dev/" + string(name[:i])
|
||||
return strings.Replace(s, "ptm", "pts", -1), nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("TIOCPTYGNAME string not NUL-terminated")
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package pty
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func posixOpenpt(oflag int) (fd int, err error) {
|
||||
r0, _, e1 := syscall.Syscall(syscall.SYS_POSIX_OPENPT, uintptr(oflag), 0, 0)
|
||||
fd = int(r0)
|
||||
if e1 != 0 {
|
||||
err = e1
|
||||
}
|
||||
return fd, err
|
||||
}
|
||||
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
fd, err := posixOpenpt(syscall.O_RDWR | syscall.O_CLOEXEC)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
p := os.NewFile(uintptr(fd), "/dev/pts")
|
||||
// In case of error after this point, make sure we close the pts fd.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = p.Close() // Best effort.
|
||||
}
|
||||
}()
|
||||
|
||||
sname, err := ptsname(p)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t, err := os.OpenFile("/dev/"+sname, os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return p, t, nil
|
||||
}
|
||||
|
||||
func isptmaster(fd uintptr) (bool, error) {
|
||||
err := ioctl(fd, syscall.TIOCPTMASTER, 0)
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
emptyFiodgnameArg fiodgnameArg
|
||||
ioctlFIODGNAME = _IOW('f', 120, unsafe.Sizeof(emptyFiodgnameArg))
|
||||
)
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
master, err := isptmaster(f.Fd())
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !master {
|
||||
return "", syscall.EINVAL
|
||||
}
|
||||
|
||||
const n = _C_SPECNAMELEN + 1
|
||||
var (
|
||||
buf = make([]byte, n)
|
||||
arg = fiodgnameArg{Len: n, Buf: (*byte)(unsafe.Pointer(&buf[0]))}
|
||||
)
|
||||
if err := ioctl(f.Fd(), ioctlFIODGNAME, uintptr(unsafe.Pointer(&arg))); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for i, c := range buf {
|
||||
if c == 0 {
|
||||
return string(buf[:i]), nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("FIODGNAME string not NUL-terminated")
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
p, err := os.OpenFile("/dev/ptmx", os.O_RDWR, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// In case of error after this point, make sure we close the ptmx fd.
|
||||
defer func() {
|
||||
if err != nil {
|
||||
_ = p.Close() // Best effort.
|
||||
}
|
||||
}()
|
||||
|
||||
sname, err := ptsname(p)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if err := unlockpt(p); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
t, err := os.OpenFile(sname, os.O_RDWR|syscall.O_NOCTTY, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return p, t, nil
|
||||
}
|
||||
|
||||
func ptsname(f *os.File) (string, error) {
|
||||
var n _C_uint
|
||||
err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return "/dev/pts/" + strconv.Itoa(int(n)), nil
|
||||
}
|
||||
|
||||
func unlockpt(f *os.File) error {
|
||||
var u _C_int
|
||||
// use TIOCSPTLCK with a pointer to zero to clear the lock
|
||||
return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u)))
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
/*
|
||||
* from ptm(4):
|
||||
* The PTMGET command allocates a free pseudo terminal, changes its
|
||||
* ownership to the caller, revokes the access privileges for all previous
|
||||
* users, opens the file descriptors for the pty and tty devices and
|
||||
* returns them to the caller in struct ptmget.
|
||||
*/
|
||||
|
||||
p, err := os.OpenFile("/dev/ptm", os.O_RDWR|syscall.O_CLOEXEC, 0)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
defer p.Close()
|
||||
|
||||
var ptm ptmget
|
||||
if err := ioctl(p.Fd(), uintptr(ioctl_PTMGET), uintptr(unsafe.Pointer(&ptm))); err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pty = os.NewFile(uintptr(ptm.Cfd), "/dev/ptm")
|
||||
tty = os.NewFile(uintptr(ptm.Sfd), "/dev/ptm")
|
||||
|
||||
return pty, tty, nil
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// +build !linux,!darwin,!freebsd,!dragonfly,!openbsd
|
||||
|
||||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func open() (pty, tty *os.File, err error) {
|
||||
return nil, nil, ErrUnsupported
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
// +build !windows
|
||||
|
||||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
|
||||
// and c.Stderr, calls c.Start, and returns the File of the tty's
|
||||
// corresponding pty.
|
||||
func Start(c *exec.Cmd) (pty *os.File, err error) {
|
||||
return StartWithSize(c, nil)
|
||||
}
|
||||
|
||||
// StartWithSize assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
|
||||
// and c.Stderr, calls c.Start, and returns the File of the tty's
|
||||
// corresponding pty.
|
||||
//
|
||||
// This will resize the pty to the specified size before starting the command
|
||||
func StartWithSize(c *exec.Cmd, sz *Winsize) (pty *os.File, err error) {
|
||||
pty, tty, err := Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer tty.Close()
|
||||
if sz != nil {
|
||||
err = Setsize(pty, sz)
|
||||
if err != nil {
|
||||
pty.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if c.Stdout == nil {
|
||||
c.Stdout = tty
|
||||
}
|
||||
if c.Stderr == nil {
|
||||
c.Stderr = tty
|
||||
}
|
||||
if c.Stdin == nil {
|
||||
c.Stdin = tty
|
||||
}
|
||||
if c.SysProcAttr == nil {
|
||||
c.SysProcAttr = &syscall.SysProcAttr{}
|
||||
}
|
||||
c.SysProcAttr.Setctty = true
|
||||
c.SysProcAttr.Setsid = true
|
||||
c.SysProcAttr.Ctty = int(tty.Fd())
|
||||
err = c.Start()
|
||||
if err != nil {
|
||||
pty.Close()
|
||||
return nil, err
|
||||
}
|
||||
return pty, err
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
// +build ignore
|
||||
|
||||
package pty
|
||||
|
||||
import "C"
|
||||
|
||||
type (
|
||||
_C_int C.int
|
||||
_C_uint C.uint
|
||||
)
|
|
@ -0,0 +1,17 @@
|
|||
// +build ignore
|
||||
|
||||
package pty
|
||||
|
||||
/*
|
||||
#define _KERNEL
|
||||
#include <sys/conf.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/filio.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
const (
|
||||
_C_SPECNAMELEN = C.SPECNAMELEN /* max length of devicename */
|
||||
)
|
||||
|
||||
type fiodgnameArg C.struct_fiodname_args
|
|
@ -0,0 +1,15 @@
|
|||
// +build ignore
|
||||
|
||||
package pty
|
||||
|
||||
/*
|
||||
#include <sys/param.h>
|
||||
#include <sys/filio.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
const (
|
||||
_C_SPECNAMELEN = C.SPECNAMELEN /* max length of devicename */
|
||||
)
|
||||
|
||||
type fiodgnameArg C.struct_fiodgname_arg
|
|
@ -0,0 +1,14 @@
|
|||
// +build ignore
|
||||
|
||||
package pty
|
||||
|
||||
/*
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/tty.h>
|
||||
*/
|
||||
import "C"
|
||||
|
||||
type ptmget C.struct_ptmget
|
||||
|
||||
var ioctl_PTMGET = C.PTMGET
|
|
@ -0,0 +1,64 @@
|
|||
// +build !windows
|
||||
|
||||
package pty
|
||||
|
||||
import (
|
||||
"os"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// InheritSize applies the terminal size of pty to tty. This should be run
|
||||
// in a signal handler for syscall.SIGWINCH to automatically resize the tty when
|
||||
// the pty receives a window size change notification.
|
||||
func InheritSize(pty, tty *os.File) error {
|
||||
size, err := GetsizeFull(pty)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = Setsize(tty, size)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setsize resizes t to s.
|
||||
func Setsize(t *os.File, ws *Winsize) error {
|
||||
return windowRectCall(ws, t.Fd(), syscall.TIOCSWINSZ)
|
||||
}
|
||||
|
||||
// GetsizeFull returns the full terminal size description.
|
||||
func GetsizeFull(t *os.File) (size *Winsize, err error) {
|
||||
var ws Winsize
|
||||
err = windowRectCall(&ws, t.Fd(), syscall.TIOCGWINSZ)
|
||||
return &ws, err
|
||||
}
|
||||
|
||||
// Getsize returns the number of rows (lines) and cols (positions
|
||||
// in each line) in terminal t.
|
||||
func Getsize(t *os.File) (rows, cols int, err error) {
|
||||
ws, err := GetsizeFull(t)
|
||||
return int(ws.Rows), int(ws.Cols), err
|
||||
}
|
||||
|
||||
// Winsize describes the terminal size.
|
||||
type Winsize struct {
|
||||
Rows uint16 // ws_row: Number of rows (in cells)
|
||||
Cols uint16 // ws_col: Number of columns (in cells)
|
||||
X uint16 // ws_xpixel: Width in pixels
|
||||
Y uint16 // ws_ypixel: Height in pixels
|
||||
}
|
||||
|
||||
func windowRectCall(ws *Winsize, fd, a2 uintptr) error {
|
||||
_, _, errno := syscall.Syscall(
|
||||
syscall.SYS_IOCTL,
|
||||
fd,
|
||||
a2,
|
||||
uintptr(unsafe.Pointer(ws)),
|
||||
)
|
||||
if errno != 0 {
|
||||
return syscall.Errno(errno)
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
// +build arm64
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,14 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_dragonfly.go
|
||||
|
||||
package pty
|
||||
|
||||
const (
|
||||
_C_SPECNAMELEN = 0x3f
|
||||
)
|
||||
|
||||
type fiodgnameArg struct {
|
||||
Name *byte
|
||||
Len uint32
|
||||
Pad_cgo_0 [4]byte
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_freebsd.go
|
||||
|
||||
package pty
|
||||
|
||||
const (
|
||||
_C_SPECNAMELEN = 0x3f
|
||||
)
|
||||
|
||||
type fiodgnameArg struct {
|
||||
Len int32
|
||||
Buf *byte
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_freebsd.go
|
||||
|
||||
package pty
|
||||
|
||||
const (
|
||||
_C_SPECNAMELEN = 0x3f
|
||||
)
|
||||
|
||||
type fiodgnameArg struct {
|
||||
Len int32
|
||||
Pad_cgo_0 [4]byte
|
||||
Buf *byte
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_freebsd.go
|
||||
|
||||
package pty
|
||||
|
||||
const (
|
||||
_C_SPECNAMELEN = 0x3f
|
||||
)
|
||||
|
||||
type fiodgnameArg struct {
|
||||
Len int32
|
||||
Buf *byte
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
// +build linux
|
||||
// +build mips mipsle mips64 mips64le
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,13 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_openbsd.go
|
||||
|
||||
package pty
|
||||
|
||||
type ptmget struct {
|
||||
Cfd int32
|
||||
Sfd int32
|
||||
Cn [16]int8
|
||||
Sn [16]int8
|
||||
}
|
||||
|
||||
var ioctl_PTMGET = 0x40287401
|
|
@ -0,0 +1,13 @@
|
|||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types_openbsd.go
|
||||
|
||||
package pty
|
||||
|
||||
type ptmget struct {
|
||||
Cfd int32
|
||||
Sfd int32
|
||||
Cn [16]int8
|
||||
Sn [16]int8
|
||||
}
|
||||
|
||||
var ioctl_PTMGET = 0x40287401
|
|
@ -0,0 +1,11 @@
|
|||
// +build ppc64
|
||||
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
// +build ppc64le
|
||||
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -0,0 +1,11 @@
|
|||
// +build s390x
|
||||
|
||||
// Created by cgo -godefs - DO NOT EDIT
|
||||
// cgo -godefs types.go
|
||||
|
||||
package pty
|
||||
|
||||
type (
|
||||
_C_int int32
|
||||
_C_uint uint32
|
||||
)
|
|
@ -244,6 +244,7 @@
|
|||
{"path":"github.com/hpcloud/tail/watch","checksumSHA1":"TP4OAv5JMtzj2TB6OQBKqauaKDc=","revision":"37f4271387456dd1bf82ab1ad9229f060cc45386","revisionTime":"2017-08-14T16:06:53Z"},
|
||||
{"path":"github.com/jmespath/go-jmespath","checksumSHA1":"3/Bhy+ua/DCv2ElMD5GzOYSGN6g=","comment":"0.2.2-2-gc01cf91","revision":"c01cf91b011868172fdcd9f41838e80c9d716264"},
|
||||
{"path":"github.com/kr/pretty","checksumSHA1":"eOXF2PEvYLMeD8DSzLZJWbjYzco=","revision":"cfb55aafdaf3ec08f0db22699ab822c50091b1c4","revisionTime":"2016-08-23T17:07:15Z"},
|
||||
{"path":"github.com/kr/pty","checksumSHA1":"WD7GMln/NoduJr0DbumjOE59xI8=","revision":"b6e1bdd4a4f88614e0c6e5e8089c7abed98aae17","revisionTime":"2019-04-01T03:15:51Z"},
|
||||
{"path":"github.com/kr/text","checksumSHA1":"uulQHQ7IsRKqDudBC8Go9J0gtAc=","revision":"7cafcd837844e784b526369c9bce262804aebc60","revisionTime":"2016-05-04T02:26:26Z"},
|
||||
{"path":"github.com/mattn/go-colorable","checksumSHA1":"SEnjvwVyfuU2xBaOfXfwPD5MZqk=","revision":"efa589957cd060542a26d2dd7832fd6a6c6c3ade","revisionTime":"2018-03-10T13:32:14Z"},
|
||||
{"path":"github.com/mattn/go-isatty","checksumSHA1":"AZO2VGorXTMDiSVUih3k73vORHY=","revision":"6ca4dbf54d38eea1a992b3c722a76a5d1c4cb25c","revisionTime":"2017-11-07T05:05:31Z"},
|
||||
|
|
Loading…
Reference in New Issue