Add console pkg and update go-runc

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
Michael Crosby 2017-01-26 10:33:33 -08:00
parent 07c81ccac4
commit 8e5e9ae70e
7 changed files with 279 additions and 47 deletions

View file

@ -1,5 +1,7 @@
# go-runc client for runc; master as of 01/20/2017
github.com/crosbymichael/go-runc f36917a18b3d962aee066063cba0bcff44e338ca
github.com/crosbymichael/go-runc d300412371ca6865a40bd4559599bb370889e2aa
# console pkg;
github.com/crosbymichael/console 4bf9d88357031b516b3794a2594b6d060a29c59c
# go-metrics client to prometheus; master as of 12/16/2016
github.com/docker/go-metrics 0f35294225552d968a13f9c5bc71a3fa44b2eb87
# prometheus client; latest release as of 12/16/2016

24
vendor/github.com/crosbymichael/console/LICENSE generated vendored Normal file
View file

@ -0,0 +1,24 @@
Copyright (c) 2017-infinity Michael Crosby. crosbymichael@gmail.com
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.

54
vendor/github.com/crosbymichael/console/console.go generated vendored Normal file
View file

@ -0,0 +1,54 @@
package console
import (
"errors"
"io"
"os"
)
var ErrNotAConsole = errors.New("provided file is not a console")
type Console interface {
io.Reader
io.Writer
io.Closer
// Resize resizes the console to the provided window size
Resize(WinSize) error
// ResizeFrom resizes the calling console to the size of the
// provided console
ResizeFrom(Console) error
// SetRaw sets the console in raw mode
SetRaw() error
// Reset restores the console to its orignal state
Reset() error
// Size returns the window size of the console
Size() (WinSize, error)
}
// WinSize specifies the window size of the console
type WinSize struct {
// Width of the console
Width uint16
// Height of the console
Height uint16
x uint16
y uint16
}
// Current returns the current processes console
func Current() Console {
return &master{
f: os.Stdin,
}
}
// ConsoleFromFile returns a console using the provided file
func ConsoleFromFile(f *os.File) (Console, error) {
if err := checkConsole(f); err != nil {
return nil, err
}
return &master{
f: f,
}, nil
}

View file

@ -0,0 +1,105 @@
package console
// #include <termios.h>
import "C"
import (
"os"
"syscall"
"unsafe"
)
// NewPty creates a new pty pair
// The master is returned as the first console and a string
// with the path to the pty slave is returned as the second
func NewPty() (Console, string, error) {
f, err := os.OpenFile("/dev/ptmx", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_CLOEXEC, 0)
if err != nil {
return nil, "", err
}
if err := saneTerminal(f); err != nil {
return nil, "", err
}
slave, err := ptsname(f)
if err != nil {
return nil, "", err
}
if err := unlockpt(f); err != nil {
return nil, "", err
}
return &master{
f: f,
}, slave, nil
}
type master struct {
f *os.File
termios *syscall.Termios
}
func (m *master) Read(b []byte) (int, error) {
return m.f.Read(b)
}
func (m *master) Write(b []byte) (int, error) {
return m.f.Write(b)
}
func (m *master) Close() error {
return m.f.Close()
}
func (m *master) Resize(ws WinSize) error {
return ioctl(
m.f.Fd(),
uintptr(syscall.TIOCSWINSZ),
uintptr(unsafe.Pointer(&ws)),
)
}
func (m *master) ResizeFrom(c Console) error {
ws, err := c.Size()
if err != nil {
return err
}
return m.Resize(ws)
}
func (m *master) Reset() error {
if m.termios == nil {
return nil
}
return tcset(m.f.Fd(), m.termios)
}
func (m *master) SetRaw() error {
m.termios = &syscall.Termios{}
if err := tcget(m.f.Fd(), m.termios); err != nil {
return err
}
rawState := *m.termios
C.cfmakeraw((*C.struct_termios)(unsafe.Pointer(&rawState)))
rawState.Oflag = rawState.Oflag | C.OPOST
return tcset(m.f.Fd(), &rawState)
}
func (m *master) Size() (WinSize, error) {
var ws WinSize
if err := ioctl(
m.f.Fd(),
uintptr(syscall.TIOCGWINSZ),
uintptr(unsafe.Pointer(&ws)),
); err != nil {
return ws, err
}
return ws, nil
}
// checkConsole checks if the provided file is a console
func checkConsole(f *os.File) error {
var termios syscall.Termios
if tcget(f.Fd(), &termios) != nil {
return ErrNotAConsole
}
return nil
}

52
vendor/github.com/crosbymichael/console/tc.go generated vendored Normal file
View file

@ -0,0 +1,52 @@
// +build linux
package console
import (
"fmt"
"os"
"syscall"
"unsafe"
)
func tcget(fd uintptr, p *syscall.Termios) error {
return ioctl(fd, syscall.TCGETS, uintptr(unsafe.Pointer(p)))
}
func tcset(fd uintptr, p *syscall.Termios) error {
return ioctl(fd, syscall.TCSETS, uintptr(unsafe.Pointer(p)))
}
func ioctl(fd, flag, data uintptr) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, flag, data); err != 0 {
return err
}
return nil
}
// unlockpt unlocks the slave pseudoterminal device corresponding to the master pseudoterminal referred to by f.
// unlockpt should be called before opening the slave side of a pty.
func unlockpt(f *os.File) error {
var u int32
return ioctl(f.Fd(), syscall.TIOCSPTLCK, uintptr(unsafe.Pointer(&u)))
}
// ptsname retrieves the name of the first available pts for the given master.
func ptsname(f *os.File) (string, error) {
var n int32
if err := ioctl(f.Fd(), syscall.TIOCGPTN, uintptr(unsafe.Pointer(&n))); err != nil {
return "", err
}
return fmt.Sprintf("/dev/pts/%d", n), nil
}
func saneTerminal(f *os.File) error {
// Go doesn't have a wrapper for any of the termios ioctls.
var termios syscall.Termios
if err := tcget(f.Fd(), &termios); err != nil {
return err
}
// Set -onlcr so we don't have to deal with \r.
termios.Oflag &^= syscall.ONLCR
return tcset(f.Fd(), &termios)
}

View file

@ -3,22 +3,26 @@ package runc
import (
"fmt"
"net"
"os"
"path/filepath"
"github.com/docker/docker/pkg/term"
"github.com/crosbymichael/console"
"github.com/opencontainers/runc/libcontainer/utils"
)
// NewConsoleSocket creates a new unix socket at the provided path to accept a
// pty master created by runc for use by the container
func NewConsoleSocket(path string) (*ConsoleSocket, error) {
l, err := net.Listen("unix", path)
abs, err := filepath.Abs(path)
if err != nil {
return nil, err
}
l, err := net.Listen("unix", abs)
if err != nil {
return nil, err
}
return &ConsoleSocket{
l: l,
path: path,
path: abs,
}, nil
}
@ -34,7 +38,7 @@ func (c *ConsoleSocket) Path() string {
}
// ReceiveMaster blocks until the socket receives the pty master
func (c *ConsoleSocket) ReceiveMaster() (*Console, error) {
func (c *ConsoleSocket) ReceiveMaster() (console.Console, error) {
conn, err := c.l.Accept()
if err != nil {
return nil, err
@ -52,9 +56,7 @@ func (c *ConsoleSocket) ReceiveMaster() (*Console, error) {
if err != nil {
return nil, err
}
return &Console{
master: f,
}, nil
return console.ConsoleFromFile(f)
}
// Close closes the unix socket
@ -69,31 +71,3 @@ type WinSize struct {
// Height of the console
Height uint16
}
// Console is a pty master
type Console struct {
master *os.File
}
// Read from the console
func (c *Console) Read(b []byte) (int, error) {
return c.master.Read(b)
}
// Write writes to the console
func (c *Console) Write(b []byte) (int, error) {
return c.master.Write(b)
}
// Resize the console
func (c *Console) Resize(ws WinSize) error {
return term.SetWinsize(c.master.Fd(), &term.Winsize{
Width: ws.Width,
Height: ws.Height,
})
}
// Close the console
func (c *Console) Close() error {
return c.master.Close()
}

View file

@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
"time"
@ -73,9 +74,13 @@ type CreateOpts struct {
NoNewKeyring bool
}
func (o *CreateOpts) args() (out []string) {
func (o *CreateOpts) args() (out []string, err error) {
if o.PidFile != "" {
out = append(out, "--pid-file", o.PidFile)
abs, err := filepath.Abs(o.PidFile)
if err != nil {
return nil, err
}
out = append(out, "--pid-file", abs)
}
if o.ConsoleSocket != nil {
out = append(out, "--console-socket", o.ConsoleSocket.Path())
@ -89,17 +94,21 @@ func (o *CreateOpts) args() (out []string) {
if o.Detach {
out = append(out, "--detach")
}
return out
return out, nil
}
// Create creates a new container and returns its pid if it was created successfully
func (r *Runc) Create(context context.Context, id, bundle string, opts *CreateOpts) error {
args := []string{"create", "--bundle", bundle}
if opts != nil {
args = append(args, opts.args()...)
oargs, err := opts.args()
if err != nil {
return err
}
args = append(args, oargs...)
}
cmd := r.command(context, append(args, id)...)
if opts != nil {
if opts != nil && opts.IO != nil {
opts.Set(cmd)
}
if cmd.Stdout == nil && cmd.Stderr == nil {
@ -138,7 +147,7 @@ type ExecOpts struct {
Detach bool
}
func (o *ExecOpts) args() (out []string) {
func (o *ExecOpts) args() (out []string, err error) {
out = append(out, "--user", fmt.Sprintf("%d:%d", o.Uid, o.Gid))
if o.Tty {
out = append(out, "--tty")
@ -153,9 +162,13 @@ func (o *ExecOpts) args() (out []string) {
out = append(out, "--detach")
}
if o.PidFile != "" {
out = append(out, "--pid-file", o.PidFile)
abs, err := filepath.Abs(o.PidFile)
if err != nil {
return nil, err
}
out = append(out, "--pid-file", abs)
}
return out
return out, nil
}
// Exec executres and additional process inside the container based on a full
@ -173,7 +186,11 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts
}
args := []string{"exec", "--process", f.Name()}
if opts != nil {
args = append(args, opts.args()...)
oargs, err := opts.args()
if err != nil {
return err
}
args = append(args, oargs...)
}
cmd := r.command(context, append(args, id)...)
if opts != nil {
@ -187,7 +204,11 @@ func (r *Runc) Exec(context context.Context, id string, spec specs.Process, opts
func (r *Runc) Run(context context.Context, id, bundle string, opts *CreateOpts) (int, error) {
args := []string{"run", "--bundle", bundle}
if opts != nil {
args = append(args, opts.args()...)
oargs, err := opts.args()
if err != nil {
return -1, err
}
args = append(args, oargs...)
}
cmd := r.command(context, append(args, id)...)
if opts != nil {