33ad2fe318
ConnCallback lets you wrap connection objects for timeouts and limiting
113 lines
2.4 KiB
Go
113 lines
2.4 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
|
|
"github.com/docker/docker/api/types"
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/client"
|
|
"github.com/docker/docker/pkg/stdcopy"
|
|
"github.com/gliderlabs/ssh"
|
|
)
|
|
|
|
func main() {
|
|
ssh.Handle(func(sess ssh.Session) {
|
|
_, _, isTty := sess.Pty()
|
|
cfg := &container.Config{
|
|
Image: sess.User(),
|
|
Cmd: sess.Command(),
|
|
Env: sess.Environ(),
|
|
Tty: isTty,
|
|
OpenStdin: true,
|
|
AttachStderr: true,
|
|
AttachStdin: true,
|
|
AttachStdout: true,
|
|
StdinOnce: true,
|
|
Volumes: make(map[string]struct{}),
|
|
}
|
|
err, status, cleanup := dockerRun(cfg, sess)
|
|
defer cleanup()
|
|
if err != nil {
|
|
fmt.Fprintln(sess, err)
|
|
log.Println(err)
|
|
}
|
|
sess.Exit(int(status))
|
|
})
|
|
|
|
log.Println("starting ssh server on port 2222...")
|
|
log.Fatal(ssh.ListenAndServe(":2222", nil))
|
|
}
|
|
|
|
func dockerRun(cfg *container.Config, sess ssh.Session) (err error, status int64, cleanup func()) {
|
|
docker, err := client.NewEnvClient()
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
status = 255
|
|
cleanup = func() {}
|
|
ctx := context.Background()
|
|
res, err := docker.ContainerCreate(ctx, cfg, nil, nil, "")
|
|
if err != nil {
|
|
return
|
|
}
|
|
cleanup = func() {
|
|
docker.ContainerRemove(ctx, res.ID, types.ContainerRemoveOptions{})
|
|
}
|
|
opts := types.ContainerAttachOptions{
|
|
Stdin: cfg.AttachStdin,
|
|
Stdout: cfg.AttachStdout,
|
|
Stderr: cfg.AttachStderr,
|
|
Stream: true,
|
|
}
|
|
stream, err := docker.ContainerAttach(ctx, res.ID, opts)
|
|
if err != nil {
|
|
return
|
|
}
|
|
cleanup = func() {
|
|
docker.ContainerRemove(ctx, res.ID, types.ContainerRemoveOptions{})
|
|
stream.Close()
|
|
}
|
|
outputErr := make(chan error)
|
|
go func() {
|
|
var err error
|
|
if cfg.Tty {
|
|
_, err = io.Copy(sess, stream.Reader)
|
|
} else {
|
|
_, err = stdcopy.StdCopy(sess, sess.Stderr(), stream.Reader)
|
|
}
|
|
outputErr <- err
|
|
}()
|
|
go func() {
|
|
defer stream.CloseWrite()
|
|
io.Copy(stream.Conn, sess)
|
|
}()
|
|
err = docker.ContainerStart(ctx, res.ID, types.ContainerStartOptions{})
|
|
if err != nil {
|
|
return
|
|
}
|
|
if cfg.Tty {
|
|
_, winCh, _ := sess.Pty()
|
|
go func() {
|
|
for win := range winCh {
|
|
err := docker.ContainerResize(ctx, res.ID, types.ResizeOptions{
|
|
Height: uint(win.Height),
|
|
Width: uint(win.Width),
|
|
})
|
|
if err != nil {
|
|
log.Println(err)
|
|
break
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
status, err = docker.ContainerWait(ctx, res.ID)
|
|
if err != nil {
|
|
return
|
|
}
|
|
err = <-outputErr
|
|
return
|
|
}
|