summaryrefslogtreecommitdiff
path: root/execdriver
diff options
context:
space:
mode:
authorunclejack <unclejack@users.noreply.github.com>2014-04-09 01:56:01 +0300
committerunclejack <unclejack@users.noreply.github.com>2014-04-09 01:56:01 +0300
commite128a606e39fa63c6b4fd6e53a1d88cf00aad868 (patch)
tree199ee7eb6678ffecd2ddad95fce794c795ad5183 /execdriver
parent143c9707a9fafc39e1d9747f528db97b2564f01e (diff)
parentdc9c28f51d669d6b09e81c2381f800f1a33bb659 (diff)
downloaddocker-release-0.10.tar.gz
Merge pull request #5079 from unclejack/bump_v0.10.0release-0.100.10.1-hotfixes
Bump version to v0.10.0
Diffstat (limited to 'execdriver')
-rw-r--r--execdriver/MAINTAINERS2
-rw-r--r--execdriver/driver.go127
-rw-r--r--execdriver/lxc/driver.go389
-rw-r--r--execdriver/lxc/info.go50
-rw-r--r--execdriver/lxc/info_test.go36
-rw-r--r--execdriver/lxc/init.go146
-rw-r--r--execdriver/lxc/lxc_init_linux.go11
-rw-r--r--execdriver/lxc/lxc_init_unsupported.go7
-rw-r--r--execdriver/lxc/lxc_template.go147
-rw-r--r--execdriver/lxc/lxc_template_unit_test.go125
-rw-r--r--execdriver/native/default_template.go90
-rw-r--r--execdriver/native/driver.go251
-rw-r--r--execdriver/native/info.go21
-rw-r--r--execdriver/native/term.go42
-rw-r--r--execdriver/pipes.go23
-rw-r--r--execdriver/termconsole.go126
16 files changed, 0 insertions, 1593 deletions
diff --git a/execdriver/MAINTAINERS b/execdriver/MAINTAINERS
deleted file mode 100644
index e53d933d47..0000000000
--- a/execdriver/MAINTAINERS
+++ /dev/null
@@ -1,2 +0,0 @@
-Michael Crosby <michael@crosbymichael.com> (@crosbymichael)
-Guillaume Charmes <guillaume@dotcloud.com> (@creack)
diff --git a/execdriver/driver.go b/execdriver/driver.go
deleted file mode 100644
index ec8f48f52d..0000000000
--- a/execdriver/driver.go
+++ /dev/null
@@ -1,127 +0,0 @@
-package execdriver
-
-import (
- "errors"
- "io"
- "os"
- "os/exec"
-)
-
-var (
- ErrNotRunning = errors.New("Process could not be started")
- ErrWaitTimeoutReached = errors.New("Wait timeout reached")
- ErrDriverAlreadyRegistered = errors.New("A driver already registered this docker init function")
- ErrDriverNotFound = errors.New("The requested docker init has not been found")
-)
-
-var dockerInitFcts map[string]InitFunc
-
-type (
- StartCallback func(*Command)
- InitFunc func(i *InitArgs) error
-)
-
-func RegisterInitFunc(name string, fct InitFunc) error {
- if dockerInitFcts == nil {
- dockerInitFcts = make(map[string]InitFunc)
- }
- if _, ok := dockerInitFcts[name]; ok {
- return ErrDriverAlreadyRegistered
- }
- dockerInitFcts[name] = fct
- return nil
-}
-
-func GetInitFunc(name string) (InitFunc, error) {
- fct, ok := dockerInitFcts[name]
- if !ok {
- return nil, ErrDriverNotFound
- }
- return fct, nil
-}
-
-// Args provided to the init function for a driver
-type InitArgs struct {
- User string
- Gateway string
- Ip string
- WorkDir string
- Privileged bool
- Env []string
- Args []string
- Mtu int
- Driver string
- Console string
- Pipe int
- Root string
-}
-
-// Driver specific information based on
-// processes registered with the driver
-type Info interface {
- IsRunning() bool
-}
-
-// Terminal in an interface for drivers to implement
-// if they want to support Close and Resize calls from
-// the core
-type Terminal interface {
- io.Closer
- Resize(height, width int) error
-}
-
-type TtyTerminal interface {
- Master() *os.File
-}
-
-type Driver interface {
- Run(c *Command, pipes *Pipes, startCallback StartCallback) (int, error) // Run executes the process and blocks until the process exits and returns the exit code
- Kill(c *Command, sig int) error
- Name() string // Driver name
- Info(id string) Info // "temporary" hack (until we move state from core to plugins)
- GetPidsForContainer(id string) ([]int, error) // Returns a list of pids for the given container.
-}
-
-// Network settings of the container
-type Network struct {
- Gateway string `json:"gateway"`
- IPAddress string `json:"ip"`
- Bridge string `json:"bridge"`
- IPPrefixLen int `json:"ip_prefix_len"`
- Mtu int `json:"mtu"`
-}
-
-type Resources struct {
- Memory int64 `json:"memory"`
- MemorySwap int64 `json:"memory_swap"`
- CpuShares int64 `json:"cpu_shares"`
-}
-
-// Process wrapps an os/exec.Cmd to add more metadata
-type Command struct {
- exec.Cmd `json:"-"`
-
- ID string `json:"id"`
- Privileged bool `json:"privileged"`
- User string `json:"user"`
- Rootfs string `json:"rootfs"` // root fs of the container
- InitPath string `json:"initpath"` // dockerinit
- Entrypoint string `json:"entrypoint"`
- Arguments []string `json:"arguments"`
- WorkingDir string `json:"working_dir"`
- ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
- Tty bool `json:"tty"`
- Network *Network `json:"network"` // if network is nil then networking is disabled
- Config []string `json:"config"` // generic values that specific drivers can consume
- Resources *Resources `json:"resources"`
-
- Terminal Terminal `json:"-"` // standard or tty terminal
- Console string `json:"-"` // dev/console path
- ContainerPid int `json:"container_pid"` // the pid for the process inside a container
-}
-
-// Return the pid of the process
-// If the process is nil -1 will be returned
-func (c *Command) Pid() int {
- return c.ContainerPid
-}
diff --git a/execdriver/lxc/driver.go b/execdriver/lxc/driver.go
deleted file mode 100644
index 765a52ee43..0000000000
--- a/execdriver/lxc/driver.go
+++ /dev/null
@@ -1,389 +0,0 @@
-package lxc
-
-import (
- "fmt"
- "github.com/dotcloud/docker/execdriver"
- "github.com/dotcloud/docker/pkg/cgroups"
- "github.com/dotcloud/docker/utils"
- "io/ioutil"
- "log"
- "os"
- "os/exec"
- "path"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
- "time"
-)
-
-const DriverName = "lxc"
-
-func init() {
- execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
- if err := setupHostname(args); err != nil {
- return err
- }
-
- if err := setupNetworking(args); err != nil {
- return err
- }
-
- if err := setupCapabilities(args); err != nil {
- return err
- }
-
- if err := setupWorkingDirectory(args); err != nil {
- return err
- }
-
- if err := changeUser(args); err != nil {
- return err
- }
-
- path, err := exec.LookPath(args.Args[0])
- if err != nil {
- log.Printf("Unable to locate %v", args.Args[0])
- os.Exit(127)
- }
- if err := syscall.Exec(path, args.Args, os.Environ()); err != nil {
- return fmt.Errorf("dockerinit unable to execute %s - %s", path, err)
- }
- panic("Unreachable")
- })
-}
-
-type driver struct {
- root string // root path for the driver to use
- apparmor bool
- sharedRoot bool
-}
-
-func NewDriver(root string, apparmor bool) (*driver, error) {
- // setup unconfined symlink
- if err := linkLxcStart(root); err != nil {
- return nil, err
- }
- return &driver{
- apparmor: apparmor,
- root: root,
- sharedRoot: rootIsShared(),
- }, nil
-}
-
-func (d *driver) Name() string {
- version := d.version()
- return fmt.Sprintf("%s-%s", DriverName, version)
-}
-
-func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
- if err := execdriver.SetTerminal(c, pipes); err != nil {
- return -1, err
- }
- configPath, err := d.generateLXCConfig(c)
- if err != nil {
- return -1, err
- }
- params := []string{
- "lxc-start",
- "-n", c.ID,
- "-f", configPath,
- "--",
- c.InitPath,
- "-driver",
- DriverName,
- }
-
- if c.Network != nil {
- params = append(params,
- "-g", c.Network.Gateway,
- "-i", fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
- "-mtu", strconv.Itoa(c.Network.Mtu),
- )
- }
-
- if c.User != "" {
- params = append(params, "-u", c.User)
- }
-
- if c.Privileged {
- if d.apparmor {
- params[0] = path.Join(d.root, "lxc-start-unconfined")
-
- }
- params = append(params, "-privileged")
- }
-
- if c.WorkingDir != "" {
- params = append(params, "-w", c.WorkingDir)
- }
-
- params = append(params, "--", c.Entrypoint)
- params = append(params, c.Arguments...)
-
- if d.sharedRoot {
- // lxc-start really needs / to be non-shared, or all kinds of stuff break
- // when lxc-start unmount things and those unmounts propagate to the main
- // mount namespace.
- // What we really want is to clone into a new namespace and then
- // mount / MS_REC|MS_SLAVE, but since we can't really clone or fork
- // without exec in go we have to do this horrible shell hack...
- shellString :=
- "mount --make-rslave /; exec " +
- utils.ShellQuoteArguments(params)
-
- params = []string{
- "unshare", "-m", "--", "/bin/sh", "-c", shellString,
- }
- }
-
- var (
- name = params[0]
- arg = params[1:]
- )
- aname, err := exec.LookPath(name)
- if err != nil {
- aname = name
- }
- c.Path = aname
- c.Args = append([]string{name}, arg...)
-
- if err := c.Start(); err != nil {
- return -1, err
- }
-
- var (
- waitErr error
- waitLock = make(chan struct{})
- )
- go func() {
- if err := c.Wait(); err != nil {
- if _, ok := err.(*exec.ExitError); !ok { // Do not propagate the error if it's simply a status code != 0
- waitErr = err
- }
- }
- close(waitLock)
- }()
-
- // Poll lxc for RUNNING status
- pid, err := d.waitForStart(c, waitLock)
- if err != nil {
- return -1, err
- }
- c.ContainerPid = pid
-
- if startCallback != nil {
- startCallback(c)
- }
-
- <-waitLock
-
- return getExitCode(c), waitErr
-}
-
-/// Return the exit code of the process
-// if the process has not exited -1 will be returned
-func getExitCode(c *execdriver.Command) int {
- if c.ProcessState == nil {
- return -1
- }
- return c.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
-}
-
-func (d *driver) Kill(c *execdriver.Command, sig int) error {
- return KillLxc(c.ID, sig)
-}
-
-func (d *driver) version() string {
- var (
- version string
- output []byte
- err error
- )
- if _, errPath := exec.LookPath("lxc-version"); errPath == nil {
- output, err = exec.Command("lxc-version").CombinedOutput()
- } else {
- output, err = exec.Command("lxc-start", "--version").CombinedOutput()
- }
- if err == nil {
- version = strings.TrimSpace(string(output))
- if parts := strings.SplitN(version, ":", 2); len(parts) == 2 {
- version = strings.TrimSpace(parts[1])
- }
- }
- return version
-}
-
-func KillLxc(id string, sig int) error {
- var (
- err error
- output []byte
- )
- _, err = exec.LookPath("lxc-kill")
- if err == nil {
- output, err = exec.Command("lxc-kill", "-n", id, strconv.Itoa(sig)).CombinedOutput()
- } else {
- output, err = exec.Command("lxc-stop", "-k", "-n", id, strconv.Itoa(sig)).CombinedOutput()
- }
- if err != nil {
- return fmt.Errorf("Err: %s Output: %s", err, output)
- }
- return nil
-}
-
-// wait for the process to start and return the pid for the process
-func (d *driver) waitForStart(c *execdriver.Command, waitLock chan struct{}) (int, error) {
- var (
- err error
- output []byte
- )
- // We wait for the container to be fully running.
- // Timeout after 5 seconds. In case of broken pipe, just retry.
- // Note: The container can run and finish correctly before
- // the end of this loop
- for now := time.Now(); time.Since(now) < 5*time.Second; {
- select {
- case <-waitLock:
- // If the process dies while waiting for it, just return
- return -1, nil
- default:
- }
-
- output, err = d.getInfo(c.ID)
- if err != nil {
- output, err = d.getInfo(c.ID)
- if err != nil {
- return -1, err
- }
- }
- info, err := parseLxcInfo(string(output))
- if err != nil {
- return -1, err
- }
- if info.Running {
- return info.Pid, nil
- }
- time.Sleep(50 * time.Millisecond)
- }
- return -1, execdriver.ErrNotRunning
-}
-
-func (d *driver) getInfo(id string) ([]byte, error) {
- return exec.Command("lxc-info", "-n", id).CombinedOutput()
-}
-
-type info struct {
- ID string
- driver *driver
-}
-
-func (i *info) IsRunning() bool {
- var running bool
-
- output, err := i.driver.getInfo(i.ID)
- if err != nil {
- utils.Errorf("Error getting info for lxc container %s: %s (%s)", i.ID, err, output)
- return false
- }
- if strings.Contains(string(output), "RUNNING") {
- running = true
- }
- return running
-}
-
-func (d *driver) Info(id string) execdriver.Info {
- return &info{
- ID: id,
- driver: d,
- }
-}
-
-func (d *driver) GetPidsForContainer(id string) ([]int, error) {
- pids := []int{}
-
- // cpu is chosen because it is the only non optional subsystem in cgroups
- subsystem := "cpu"
- cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
- if err != nil {
- return pids, err
- }
-
- cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
- if err != nil {
- return pids, err
- }
-
- filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
- if _, err := os.Stat(filename); os.IsNotExist(err) {
- // With more recent lxc versions use, cgroup will be in lxc/
- filename = filepath.Join(cgroupRoot, cgroupDir, "lxc", id, "tasks")
- }
-
- output, err := ioutil.ReadFile(filename)
- if err != nil {
- return pids, err
- }
- for _, p := range strings.Split(string(output), "\n") {
- if len(p) == 0 {
- continue
- }
- pid, err := strconv.Atoi(p)
- if err != nil {
- return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
- }
- pids = append(pids, pid)
- }
- return pids, nil
-}
-
-func linkLxcStart(root string) error {
- sourcePath, err := exec.LookPath("lxc-start")
- if err != nil {
- return err
- }
- targetPath := path.Join(root, "lxc-start-unconfined")
-
- if _, err := os.Lstat(targetPath); err != nil && !os.IsNotExist(err) {
- return err
- } else if err == nil {
- if err := os.Remove(targetPath); err != nil {
- return err
- }
- }
- return os.Symlink(sourcePath, targetPath)
-}
-
-// TODO: This can be moved to the mountinfo reader in the mount pkg
-func rootIsShared() bool {
- if data, err := ioutil.ReadFile("/proc/self/mountinfo"); err == nil {
- for _, line := range strings.Split(string(data), "\n") {
- cols := strings.Split(line, " ")
- if len(cols) >= 6 && cols[4] == "/" {
- return strings.HasPrefix(cols[6], "shared")
- }
- }
- }
-
- // No idea, probably safe to assume so
- return true
-}
-
-func (d *driver) generateLXCConfig(c *execdriver.Command) (string, error) {
- root := path.Join(d.root, "containers", c.ID, "config.lxc")
- fo, err := os.Create(root)
- if err != nil {
- return "", err
- }
- defer fo.Close()
-
- if err := LxcTemplateCompiled.Execute(fo, struct {
- *execdriver.Command
- AppArmor bool
- }{
- Command: c,
- AppArmor: d.apparmor,
- }); err != nil {
- return "", err
- }
- return root, nil
-}
diff --git a/execdriver/lxc/info.go b/execdriver/lxc/info.go
deleted file mode 100644
index 3b2ea0d07f..0000000000
--- a/execdriver/lxc/info.go
+++ /dev/null
@@ -1,50 +0,0 @@
-package lxc
-
-import (
- "bufio"
- "errors"
- "strconv"
- "strings"
-)
-
-var (
- ErrCannotParse = errors.New("cannot parse raw input")
-)
-
-type lxcInfo struct {
- Running bool
- Pid int
-}
-
-func parseLxcInfo(raw string) (*lxcInfo, error) {
- if raw == "" {
- return nil, ErrCannotParse
- }
- var (
- err error
- s = bufio.NewScanner(strings.NewReader(raw))
- info = &lxcInfo{}
- )
- for s.Scan() {
- text := s.Text()
-
- if s.Err() != nil {
- return nil, s.Err()
- }
-
- parts := strings.Split(text, ":")
- if len(parts) < 2 {
- continue
- }
- switch strings.TrimSpace(parts[0]) {
- case "state":
- info.Running = strings.TrimSpace(parts[1]) == "RUNNING"
- case "pid":
- info.Pid, err = strconv.Atoi(strings.TrimSpace(parts[1]))
- if err != nil {
- return nil, err
- }
- }
- }
- return info, nil
-}
diff --git a/execdriver/lxc/info_test.go b/execdriver/lxc/info_test.go
deleted file mode 100644
index edafc02511..0000000000
--- a/execdriver/lxc/info_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package lxc
-
-import (
- "testing"
-)
-
-func TestParseRunningInfo(t *testing.T) {
- raw := `
- state: RUNNING
- pid: 50`
-
- info, err := parseLxcInfo(raw)
- if err != nil {
- t.Fatal(err)
- }
- if !info.Running {
- t.Fatal("info should return a running state")
- }
- if info.Pid != 50 {
- t.Fatalf("info should have pid 50 got %d", info.Pid)
- }
-}
-
-func TestEmptyInfo(t *testing.T) {
- _, err := parseLxcInfo("")
- if err == nil {
- t.Fatal("error should not be nil")
- }
-}
-
-func TestBadInfo(t *testing.T) {
- _, err := parseLxcInfo("state")
- if err != nil {
- t.Fatal(err)
- }
-}
diff --git a/execdriver/lxc/init.go b/execdriver/lxc/init.go
deleted file mode 100644
index e138915212..0000000000
--- a/execdriver/lxc/init.go
+++ /dev/null
@@ -1,146 +0,0 @@
-package lxc
-
-import (
- "fmt"
- "github.com/dotcloud/docker/execdriver"
- "github.com/dotcloud/docker/pkg/netlink"
- "github.com/dotcloud/docker/pkg/user"
- "github.com/syndtr/gocapability/capability"
- "net"
- "os"
- "strings"
- "syscall"
-)
-
-func setupHostname(args *execdriver.InitArgs) error {
- hostname := getEnv(args, "HOSTNAME")
- if hostname == "" {
- return nil
- }
- return setHostname(hostname)
-}
-
-// Setup networking
-func setupNetworking(args *execdriver.InitArgs) error {
- if args.Ip != "" {
- // eth0
- iface, err := net.InterfaceByName("eth0")
- if err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- ip, ipNet, err := net.ParseCIDR(args.Ip)
- if err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- if err := netlink.NetworkLinkAddIp(iface, ip, ipNet); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- if err := netlink.NetworkSetMTU(iface, args.Mtu); err != nil {
- return fmt.Errorf("Unable to set MTU: %v", err)
- }
- if err := netlink.NetworkLinkUp(iface); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
-
- // loopback
- iface, err = net.InterfaceByName("lo")
- if err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- if err := netlink.NetworkLinkUp(iface); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- }
- if args.Gateway != "" {
- gw := net.ParseIP(args.Gateway)
- if gw == nil {
- return fmt.Errorf("Unable to set up networking, %s is not a valid gateway IP", args.Gateway)
- }
-
- if err := netlink.AddDefaultGw(gw); err != nil {
- return fmt.Errorf("Unable to set up networking: %v", err)
- }
- }
-
- return nil
-}
-
-// Setup working directory
-func setupWorkingDirectory(args *execdriver.InitArgs) error {
- if args.WorkDir == "" {
- return nil
- }
- if err := syscall.Chdir(args.WorkDir); err != nil {
- return fmt.Errorf("Unable to change dir to %v: %v", args.WorkDir, err)
- }
- return nil
-}
-
-// Takes care of dropping privileges to the desired user
-func changeUser(args *execdriver.InitArgs) error {
- uid, gid, suppGids, err := user.GetUserGroupSupplementary(
- args.User,
- syscall.Getuid(), syscall.Getgid(),
- )
- if err != nil {
- return err
- }
-
- if err := syscall.Setgroups(suppGids); err != nil {
- return fmt.Errorf("Setgroups failed: %v", err)
- }
- if err := syscall.Setgid(gid); err != nil {
- return fmt.Errorf("Setgid failed: %v", err)
- }
- if err := syscall.Setuid(uid); err != nil {
- return fmt.Errorf("Setuid failed: %v", err)
- }
-
- return nil
-}
-
-func setupCapabilities(args *execdriver.InitArgs) error {
- if args.Privileged {
- return nil
- }
-
- drop := []capability.Cap{
- capability.CAP_SETPCAP,
- capability.CAP_SYS_MODULE,
- capability.CAP_SYS_RAWIO,
- capability.CAP_SYS_PACCT,
- capability.CAP_SYS_ADMIN,
- capability.CAP_SYS_NICE,
- capability.CAP_SYS_RESOURCE,
- capability.CAP_SYS_TIME,
- capability.CAP_SYS_TTY_CONFIG,
- capability.CAP_MKNOD,
- capability.CAP_AUDIT_WRITE,
- capability.CAP_AUDIT_CONTROL,
- capability.CAP_MAC_OVERRIDE,
- capability.CAP_MAC_ADMIN,
- capability.CAP_NET_ADMIN,
- }
-
- c, err := capability.NewPid(os.Getpid())
- if err != nil {
- return err
- }
-
- c.Unset(capability.CAPS|capability.BOUNDS, drop...)
-
- if err := c.Apply(capability.CAPS | capability.BOUNDS); err != nil {
- return err
- }
- return nil
-}
-
-func getEnv(args *execdriver.InitArgs, key string) string {
- for _, kv := range args.Env {
- parts := strings.SplitN(kv, "=", 2)
- if parts[0] == key && len(parts) == 2 {
- return parts[1]
- }
- }
- return ""
-}
diff --git a/execdriver/lxc/lxc_init_linux.go b/execdriver/lxc/lxc_init_linux.go
deleted file mode 100644
index 7288f5877b..0000000000
--- a/execdriver/lxc/lxc_init_linux.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// +build amd64
-
-package lxc
-
-import (
- "syscall"
-)
-
-func setHostname(hostname string) error {
- return syscall.Sethostname([]byte(hostname))
-}
diff --git a/execdriver/lxc/lxc_init_unsupported.go b/execdriver/lxc/lxc_init_unsupported.go
deleted file mode 100644
index d68cb91a1e..0000000000
--- a/execdriver/lxc/lxc_init_unsupported.go
+++ /dev/null
@@ -1,7 +0,0 @@
-// +build !linux !amd64
-
-package lxc
-
-func setHostname(hostname string) error {
- panic("Not supported on darwin")
-}
diff --git a/execdriver/lxc/lxc_template.go b/execdriver/lxc/lxc_template.go
deleted file mode 100644
index 1181396a18..0000000000
--- a/execdriver/lxc/lxc_template.go
+++ /dev/null
@@ -1,147 +0,0 @@
-package lxc
-
-import (
- "github.com/dotcloud/docker/execdriver"
- "strings"
- "text/template"
-)
-
-const LxcTemplate = `
-{{if .Network}}
-# network configuration
-lxc.network.type = veth
-lxc.network.link = {{.Network.Bridge}}
-lxc.network.name = eth0
-lxc.network.mtu = {{.Network.Mtu}}
-{{else}}
-# network is disabled (-n=false)
-lxc.network.type = empty
-lxc.network.flags = up
-{{end}}
-
-# root filesystem
-{{$ROOTFS := .Rootfs}}
-lxc.rootfs = {{$ROOTFS}}
-
-# use a dedicated pts for the container (and limit the number of pseudo terminal
-# available)
-lxc.pts = 1024
-
-# disable the main console
-lxc.console = none
-
-# no controlling tty at all
-lxc.tty = 1
-
-{{if .Privileged}}
-lxc.cgroup.devices.allow = a
-{{else}}
-# no implicit access to devices
-lxc.cgroup.devices.deny = a
-
-# /dev/null and zero
-lxc.cgroup.devices.allow = c 1:3 rwm
-lxc.cgroup.devices.allow = c 1:5 rwm
-
-# consoles
-lxc.cgroup.devices.allow = c 5:1 rwm
-lxc.cgroup.devices.allow = c 5:0 rwm
-lxc.cgroup.devices.allow = c 4:0 rwm
-lxc.cgroup.devices.allow = c 4:1 rwm
-
-# /dev/urandom,/dev/random
-lxc.cgroup.devices.allow = c 1:9 rwm
-lxc.cgroup.devices.allow = c 1:8 rwm
-
-# /dev/pts/ - pts namespaces are "coming soon"
-lxc.cgroup.devices.allow = c 136:* rwm
-lxc.cgroup.devices.allow = c 5:2 rwm
-
-# tuntap
-lxc.cgroup.devices.allow = c 10:200 rwm
-
-# fuse
-#lxc.cgroup.devices.allow = c 10:229 rwm
-
-# rtc
-#lxc.cgroup.devices.allow = c 254:0 rwm
-{{end}}
-
-# standard mount point
-# Use mnt.putold as per https://bugs.launchpad.net/ubuntu/+source/lxc/+bug/986385
-lxc.pivotdir = lxc_putold
-
-# NOTICE: These mounts must be applied within the namespace
-
-# WARNING: procfs is a known attack vector and should probably be disabled
-# if your userspace allows it. eg. see http://blog.zx2c4.com/749
-lxc.mount.entry = proc {{escapeFstabSpaces $ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
-
-# WARNING: sysfs is a known attack vector and should probably be disabled
-# if your userspace allows it. eg. see http://bit.ly/T9CkqJ
-lxc.mount.entry = sysfs {{escapeFstabSpaces $ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
-
-{{if .Tty}}
-lxc.mount.entry = {{.Console}} {{escapeFstabSpaces $ROOTFS}}/dev/console none bind,rw 0 0
-{{end}}
-
-lxc.mount.entry = devpts {{escapeFstabSpaces $ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
-lxc.mount.entry = shm {{escapeFstabSpaces $ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
-
-{{if .Privileged}}
-{{if .AppArmor}}
-lxc.aa_profile = unconfined
-{{else}}
-#lxc.aa_profile = unconfined
-{{end}}
-{{end}}
-
-# limits
-{{if .Resources}}
-{{if .Resources.Memory}}
-lxc.cgroup.memory.limit_in_bytes = {{.Resources.Memory}}
-lxc.cgroup.memory.soft_limit_in_bytes = {{.Resources.Memory}}
-{{with $memSwap := getMemorySwap .Resources}}
-lxc.cgroup.memory.memsw.limit_in_bytes = {{$memSwap}}
-{{end}}
-{{end}}
-{{if .Resources.CpuShares}}
-lxc.cgroup.cpu.shares = {{.Resources.CpuShares}}
-{{end}}
-{{end}}
-
-{{if .Config}}
-{{range $value := .Config}}
-{{$value}}
-{{end}}
-{{end}}
-`
-
-var LxcTemplateCompiled *template.Template
-
-// Escape spaces in strings according to the fstab documentation, which is the
-// format for "lxc.mount.entry" lines in lxc.conf. See also "man 5 fstab".
-func escapeFstabSpaces(field string) string {
- return strings.Replace(field, " ", "\\040", -1)
-}
-
-func getMemorySwap(v *execdriver.Resources) int64 {
- // By default, MemorySwap is set to twice the size of RAM.
- // If you want to omit MemorySwap, set it to `-1'.
- if v.MemorySwap < 0 {
- return 0
- }
- return v.Memory * 2
-}
-
-func init() {
- var err error
- funcMap := template.FuncMap{
- "getMemorySwap": getMemorySwap,
- "escapeFstabSpaces": escapeFstabSpaces,
- }
- LxcTemplateCompiled, err = template.New("lxc").Funcs(funcMap).Parse(LxcTemplate)
- if err != nil {
- panic(err)
- }
-}
diff --git a/execdriver/lxc/lxc_template_unit_test.go b/execdriver/lxc/lxc_template_unit_test.go
deleted file mode 100644
index 99d6e636f5..0000000000
--- a/execdriver/lxc/lxc_template_unit_test.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package lxc
-
-import (
- "bufio"
- "fmt"
- "github.com/dotcloud/docker/execdriver"
- "io/ioutil"
- "math/rand"
- "os"
- "path"
- "strings"
- "testing"
- "time"
-)
-
-func TestLXCConfig(t *testing.T) {
- root, err := ioutil.TempDir("", "TestLXCConfig")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(root)
-
- os.MkdirAll(path.Join(root, "containers", "1"), 0777)
-
- // Memory is allocated randomly for testing
- rand.Seed(time.Now().UTC().UnixNano())
- var (
- memMin = 33554432
- memMax = 536870912
- mem = memMin + rand.Intn(memMax-memMin)
- cpuMin = 100
- cpuMax = 10000
- cpu = cpuMin + rand.Intn(cpuMax-cpuMin)
- )
-
- driver, err := NewDriver(root, false)
- if err != nil {
- t.Fatal(err)
- }
- command := &execdriver.Command{
- ID: "1",
- Resources: &execdriver.Resources{
- Memory: int64(mem),
- CpuShares: int64(cpu),
- },
- }
- p, err := driver.generateLXCConfig(command)
- if err != nil {
- t.Fatal(err)
- }
- grepFile(t, p,
- fmt.Sprintf("lxc.cgroup.memory.limit_in_bytes = %d", mem))
-
- grepFile(t, p,
- fmt.Sprintf("lxc.cgroup.memory.memsw.limit_in_bytes = %d", mem*2))
-}
-
-func TestCustomLxcConfig(t *testing.T) {
- root, err := ioutil.TempDir("", "TestCustomLxcConfig")
- if err != nil {
- t.Fatal(err)
- }
- defer os.RemoveAll(root)
-
- os.MkdirAll(path.Join(root, "containers", "1"), 0777)
-
- driver, err := NewDriver(root, false)
- if err != nil {
- t.Fatal(err)
- }
- command := &execdriver.Command{
- ID: "1",
- Privileged: false,
- Config: []string{
- "lxc.utsname = docker",
- "lxc.cgroup.cpuset.cpus = 0,1",
- },
- }
-
- p, err := driver.generateLXCConfig(command)
- if err != nil {
- t.Fatal(err)
- }
-
- grepFile(t, p, "lxc.utsname = docker")
- grepFile(t, p, "lxc.cgroup.cpuset.cpus = 0,1")
-}
-
-func grepFile(t *testing.T, path string, pattern string) {
- f, err := os.Open(path)
- if err != nil {
- t.Fatal(err)
- }
- defer f.Close()
- r := bufio.NewReader(f)
- var (
- line string
- )
- err = nil
- for err == nil {
- line, err = r.ReadString('\n')
- if strings.Contains(line, pattern) == true {
- return
- }
- }
- t.Fatalf("grepFile: pattern \"%s\" not found in \"%s\"", pattern, path)
-}
-
-func TestEscapeFstabSpaces(t *testing.T) {
- var testInputs = map[string]string{
- " ": "\\040",
- "": "",
- "/double space": "/double\\040\\040space",
- "/some long test string": "/some\\040long\\040test\\040string",
- "/var/lib/docker": "/var/lib/docker",
- " leading": "\\040leading",
- "trailing ": "trailing\\040",
- }
- for in, exp := range testInputs {
- if out := escapeFstabSpaces(in); exp != out {
- t.Logf("Expected %s got %s", exp, out)
- t.Fail()
- }
- }
-}
diff --git a/execdriver/native/default_template.go b/execdriver/native/default_template.go
deleted file mode 100644
index 6e7d597b7b..0000000000
--- a/execdriver/native/default_template.go
+++ /dev/null
@@ -1,90 +0,0 @@
-package native
-
-import (
- "fmt"
- "github.com/dotcloud/docker/execdriver"
- "github.com/dotcloud/docker/pkg/cgroups"
- "github.com/dotcloud/docker/pkg/libcontainer"
- "os"
-)
-
-// createContainer populates and configures the container type with the
-// data provided by the execdriver.Command
-func createContainer(c *execdriver.Command) *libcontainer.Container {
- container := getDefaultTemplate()
-
- container.Hostname = getEnv("HOSTNAME", c.Env)
- container.Tty = c.Tty
- container.User = c.User
- container.WorkingDir = c.WorkingDir
- container.Env = c.Env
-
- if c.Network != nil {
- container.Networks = []*libcontainer.Network{
- {
- Mtu: c.Network.Mtu,
- Address: fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
- Gateway: c.Network.Gateway,
- Type: "veth",
- Context: libcontainer.Context{
- "prefix": "veth",
- "bridge": c.Network.Bridge,
- },
- },
- }
- }
-
- container.Cgroups.Name = c.ID
- if c.Privileged {
- container.Capabilities = nil
- container.Cgroups.DeviceAccess = true
- container.Context["apparmor_profile"] = "unconfined"
- }
- if c.Resources != nil {
- container.Cgroups.CpuShares = c.Resources.CpuShares
- container.Cgroups.Memory = c.Resources.Memory
- container.Cgroups.MemorySwap = c.Resources.MemorySwap
- }
- // check to see if we are running in ramdisk to disable pivot root
- container.NoPivotRoot = os.Getenv("DOCKER_RAMDISK") != ""
-
- return container
-}
-
-// getDefaultTemplate returns the docker default for
-// the libcontainer configuration file
-func getDefaultTemplate() *libcontainer.Container {
- return &libcontainer.Container{
- Capabilities: libcontainer.Capabilities{
- libcontainer.GetCapability("SETPCAP"),
- libcontainer.GetCapability("SYS_MODULE"),
- libcontainer.GetCapability("SYS_RAWIO"),
- libcontainer.GetCapability("SYS_PACCT"),
- libcontainer.GetCapability("SYS_ADMIN"),
- libcontainer.GetCapability("SYS_NICE"),
- libcontainer.GetCapability("SYS_RESOURCE"),
- libcontainer.GetCapability("SYS_TIME"),
- libcontainer.GetCapability("SYS_TTY_CONFIG"),
- libcontainer.GetCapability("MKNOD"),
- libcontainer.GetCapability("AUDIT_WRITE"),
- libcontainer.GetCapability("AUDIT_CONTROL"),
- libcontainer.GetCapability("MAC_OVERRIDE"),
- libcontainer.GetCapability("MAC_ADMIN"),
- libcontainer.GetCapability("NET_ADMIN"),
- },
- Namespaces: libcontainer.Namespaces{
- libcontainer.GetNamespace("NEWNS"),
- libcontainer.GetNamespace("NEWUTS"),
- libcontainer.GetNamespace("NEWIPC"),
- libcontainer.GetNamespace("NEWPID"),
- libcontainer.GetNamespace("NEWNET"),
- },
- Cgroups: &cgroups.Cgroup{
- Parent: "docker",
- DeviceAccess: false,
- },
- Context: libcontainer.Context{
- "apparmor_profile": "docker-default",
- },
- }
-}
diff --git a/execdriver/native/driver.go b/execdriver/native/driver.go
deleted file mode 100644
index 452e802523..0000000000
--- a/execdriver/native/driver.go
+++ /dev/null
@@ -1,251 +0,0 @@
-package native
-
-import (
- "encoding/json"
- "fmt"
- "github.com/dotcloud/docker/execdriver"
- "github.com/dotcloud/docker/pkg/cgroups"
- "github.com/dotcloud/docker/pkg/libcontainer"
- "github.com/dotcloud/docker/pkg/libcontainer/apparmor"
- "github.com/dotcloud/docker/pkg/libcontainer/nsinit"
- "github.com/dotcloud/docker/pkg/system"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strconv"
- "strings"
- "syscall"
-)
-
-const (
- DriverName = "native"
- Version = "0.1"
-)
-
-func init() {
- execdriver.RegisterInitFunc(DriverName, func(args *execdriver.InitArgs) error {
- var (
- container *libcontainer.Container
- ns = nsinit.NewNsInit(&nsinit.DefaultCommandFactory{}, &nsinit.DefaultStateWriter{args.Root})
- )
- f, err := os.Open(filepath.Join(args.Root, "container.json"))
- if err != nil {
- return err
- }
- if err := json.NewDecoder(f).Decode(&container); err != nil {
- f.Close()
- return err
- }
- f.Close()
-
- cwd, err := os.Getwd()
- if err != nil {
- return err
- }
- syncPipe, err := nsinit.NewSyncPipeFromFd(0, uintptr(args.Pipe))
- if err != nil {
- return err
- }
- if err := ns.Init(container, cwd, args.Console, syncPipe, args.Args); err != nil {
- return err
- }
- return nil
- })
-}
-
-type driver struct {
- root string
-}
-
-func NewDriver(root string) (*driver, error) {
- if err := os.MkdirAll(root, 0700); err != nil {
- return nil, err
- }
- if err := apparmor.InstallDefaultProfile(); err != nil {
- return nil, err
- }
- return &driver{
- root: root,
- }, nil
-}
-
-func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
- if err := d.validateCommand(c); err != nil {
- return -1, err
- }
- var (
- term nsinit.Terminal
- container = createContainer(c)
- factory = &dockerCommandFactory{c: c, driver: d}
- stateWriter = &dockerStateWriter{
- callback: startCallback,
- c: c,
- dsw: &nsinit.DefaultStateWriter{filepath.Join(d.root, c.ID)},
- }
- ns = nsinit.NewNsInit(factory, stateWriter)
- args = append([]string{c.Entrypoint}, c.Arguments...)
- )
- if err := d.createContainerRoot(c.ID); err != nil {
- return -1, err
- }
- defer d.removeContainerRoot(c.ID)
-
- if c.Tty {
- term = &dockerTtyTerm{
- pipes: pipes,
- }
- } else {
- term = &dockerStdTerm{
- pipes: pipes,
- }
- }
- c.Terminal = term
- if err := d.writeContainerFile(container, c.ID); err != nil {
- return -1, err
- }
- return ns.Exec(container, term, args)
-}
-
-func (d *driver) Kill(p *execdriver.Command, sig int) error {
- err := syscall.Kill(p.Process.Pid, syscall.Signal(sig))
- d.removeContainerRoot(p.ID)
- return err
-}
-
-func (d *driver) Info(id string) execdriver.Info {
- return &info{
- ID: id,
- driver: d,
- }
-}
-
-func (d *driver) Name() string {
- return fmt.Sprintf("%s-%s", DriverName, Version)
-}
-
-// TODO: this can be improved with our driver
-// there has to be a better way to do this
-func (d *driver) GetPidsForContainer(id string) ([]int, error) {
- pids := []int{}
-
- subsystem := "devices"
- cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem)
- if err != nil {
- return pids, err
- }
- cgroupDir, err := cgroups.GetThisCgroupDir(subsystem)
- if err != nil {
- return pids, err
- }
-
- filename := filepath.Join(cgroupRoot, cgroupDir, id, "tasks")
- if _, err := os.Stat(filename); os.IsNotExist(err) {
- filename = filepath.Join(cgroupRoot, cgroupDir, "docker", id, "tasks")
- }
-
- output, err := ioutil.ReadFile(filename)
- if err != nil {
- return pids, err
- }
- for _, p := range strings.Split(string(output), "\n") {
- if len(p) == 0 {
- continue
- }
- pid, err := strconv.Atoi(p)
- if err != nil {
- return pids, fmt.Errorf("Invalid pid '%s': %s", p, err)
- }
- pids = append(pids, pid)
- }
- return pids, nil
-}
-
-func (d *driver) writeContainerFile(container *libcontainer.Container, id string) error {
- data, err := json.Marshal(container)
- if err != nil {
- return err
- }
- return ioutil.WriteFile(filepath.Join(d.root, id, "container.json"), data, 0655)
-}
-
-func (d *driver) createContainerRoot(id string) error {
- return os.MkdirAll(filepath.Join(d.root, id), 0655)
-}
-
-func (d *driver) removeContainerRoot(id string) error {
- return os.RemoveAll(filepath.Join(d.root, id))
-}
-
-func (d *driver) validateCommand(c *execdriver.Command) error {
- // we need to check the Config of the command to make sure that we
- // do not have any of the lxc-conf variables
- for _, conf := range c.Config {
- if strings.Contains(conf, "lxc") {
- return fmt.Errorf("%s is not supported by the native driver", conf)
- }
- }
- return nil
-}
-
-func getEnv(key string, env []string) string {
- for _, pair := range env {
- parts := strings.Split(pair, "=")
- if parts[0] == key {
- return parts[1]
- }
- }
- return ""
-}
-
-type dockerCommandFactory struct {
- c *execdriver.Command
- driver *driver
-}
-
-// createCommand will return an exec.Cmd with the Cloneflags set to the proper namespaces
-// defined on the container's configuration and use the current binary as the init with the
-// args provided
-func (d *dockerCommandFactory) Create(container *libcontainer.Container, console string, syncFile *os.File, args []string) *exec.Cmd {
- // we need to join the rootfs because nsinit will setup the rootfs and chroot
- initPath := filepath.Join(d.c.Rootfs, d.c.InitPath)
-
- d.c.Path = initPath
- d.c.Args = append([]string{
- initPath,
- "-driver", DriverName,
- "-console", console,
- "-pipe", "3",
- "-root", filepath.Join(d.driver.root, d.c.ID),
- "--",
- }, args...)
-
- // set this to nil so that when we set the clone flags anything else is reset
- d.c.SysProcAttr = nil
- system.SetCloneFlags(&d.c.Cmd, uintptr(nsinit.GetNamespaceFlags(container.Namespaces)))
- d.c.ExtraFiles = []*os.File{syncFile}
-
- d.c.Env = container.Env
- d.c.Dir = d.c.Rootfs
-
- return &d.c.Cmd
-}
-
-type dockerStateWriter struct {
- dsw nsinit.StateWriter
- c *execdriver.Command
- callback execdriver.StartCallback
-}
-
-func (d *dockerStateWriter) WritePid(pid int) error {
- d.c.ContainerPid = pid
- err := d.dsw.WritePid(pid)
- if d.callback != nil {
- d.callback(d.c)
- }
- return err
-}
-
-func (d *dockerStateWriter) DeletePid() error {
- return d.dsw.DeletePid()
-}
diff --git a/execdriver/native/info.go b/execdriver/native/info.go
deleted file mode 100644
index aef2f85c6b..0000000000
--- a/execdriver/native/info.go
+++ /dev/null
@@ -1,21 +0,0 @@
-package native
-
-import (
- "os"
- "path/filepath"
-)
-
-type info struct {
- ID string
- driver *driver
-}
-
-// IsRunning is determined by looking for the
-// pid file for a container. If the file exists then the
-// container is currently running
-func (i *info) IsRunning() bool {
- if _, err := os.Stat(filepath.Join(i.driver.root, i.ID, "pid")); err == nil {
- return true
- }
- return false
-}
diff --git a/execdriver/native/term.go b/execdriver/native/term.go
deleted file mode 100644
index ec69820f75..0000000000
--- a/execdriver/native/term.go
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- These types are wrappers around the libcontainer Terminal interface so that
- we can resuse the docker implementations where possible.
-*/
-package native
-
-import (
- "github.com/dotcloud/docker/execdriver"
- "io"
- "os"
- "os/exec"
-)
-
-type dockerStdTerm struct {
- execdriver.StdConsole
- pipes *execdriver.Pipes
-}
-
-func (d *dockerStdTerm) Attach(cmd *exec.Cmd) error {
- return d.AttachPipes(cmd, d.pipes)
-}
-
-func (d *dockerStdTerm) SetMaster(master *os.File) {
- // do nothing
-}
-
-type dockerTtyTerm struct {
- execdriver.TtyConsole
- pipes *execdriver.Pipes
-}
-
-func (t *dockerTtyTerm) Attach(cmd *exec.Cmd) error {
- go io.Copy(t.pipes.Stdout, t.MasterPty)
- if t.pipes.Stdin != nil {
- go io.Copy(t.MasterPty, t.pipes.Stdin)
- }
- return nil
-}
-
-func (t *dockerTtyTerm) SetMaster(master *os.File) {
- t.MasterPty = master
-}
diff --git a/execdriver/pipes.go b/execdriver/pipes.go
deleted file mode 100644
index 158219f0c5..0000000000
--- a/execdriver/pipes.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package execdriver
-
-import (
- "io"
-)
-
-// Pipes is a wrapper around a containers output for
-// stdin, stdout, stderr
-type Pipes struct {
- Stdin io.ReadCloser
- Stdout, Stderr io.Writer
-}
-
-func NewPipes(stdin io.ReadCloser, stdout, stderr io.Writer, useStdin bool) *Pipes {
- p := &Pipes{
- Stdout: stdout,
- Stderr: stderr,
- }
- if useStdin {
- p.Stdin = stdin
- }
- return p
-}
diff --git a/execdriver/termconsole.go b/execdriver/termconsole.go
deleted file mode 100644
index af6b88d3d1..0000000000
--- a/execdriver/termconsole.go
+++ /dev/null
@@ -1,126 +0,0 @@
-package execdriver
-
-import (
- "github.com/dotcloud/docker/pkg/term"
- "github.com/kr/pty"
- "io"
- "os"
- "os/exec"
-)
-
-func SetTerminal(command *Command, pipes *Pipes) error {
- var (
- term Terminal
- err error
- )
- if command.Tty {
- term, err = NewTtyConsole(command, pipes)
- } else {
- term, err = NewStdConsole(command, pipes)
- }
- if err != nil {
- return err
- }
- command.Terminal = term
- return nil
-}
-
-type TtyConsole struct {
- MasterPty *os.File
- SlavePty *os.File
-}
-
-func NewTtyConsole(command *Command, pipes *Pipes) (*TtyConsole, error) {
- ptyMaster, ptySlave, err := pty.Open()
- if err != nil {
- return nil, err
- }
- tty := &TtyConsole{
- MasterPty: ptyMaster,
- SlavePty: ptySlave,
- }
- if err := tty.AttachPipes(&command.Cmd, pipes); err != nil {
- tty.Close()
- return nil, err
- }
- command.Console = tty.SlavePty.Name()
- return tty, nil
-}
-
-func (t *TtyConsole) Master() *os.File {
- return t.MasterPty
-}
-
-func (t *TtyConsole) Resize(h, w int) error {
- return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
-}
-
-func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
- command.Stdout = t.SlavePty
- command.Stderr = t.SlavePty
-
- go func() {
- if wb, ok := pipes.Stdout.(interface {
- CloseWriters() error
- }); ok {
- defer wb.CloseWriters()
- }
- io.Copy(pipes.Stdout, t.MasterPty)
- }()
-
- if pipes.Stdin != nil {
- command.Stdin = t.SlavePty
- command.SysProcAttr.Setctty = true
-
- go func() {
- defer pipes.Stdin.Close()
- io.Copy(t.MasterPty, pipes.Stdin)
- }()
- }
- return nil
-}
-
-func (t *TtyConsole) Close() error {
- t.SlavePty.Close()
- return t.MasterPty.Close()
-}
-
-type StdConsole struct {
-}
-
-func NewStdConsole(command *Command, pipes *Pipes) (*StdConsole, error) {
- std := &StdConsole{}
-
- if err := std.AttachPipes(&command.Cmd, pipes); err != nil {
- return nil, err
- }
- return std, nil
-}
-
-func (s *StdConsole) AttachPipes(command *exec.Cmd, pipes *Pipes) error {
- command.Stdout = pipes.Stdout
- command.Stderr = pipes.Stderr
-
- if pipes.Stdin != nil {
- stdin, err := command.StdinPipe()
- if err != nil {
- return err
- }
-
- go func() {
- defer stdin.Close()
- io.Copy(stdin, pipes.Stdin)
- }()
- }
- return nil
-}
-
-func (s *StdConsole) Resize(h, w int) error {
- // we do not need to reside a non tty
- return nil
-}
-
-func (s *StdConsole) Close() error {
- // nothing to close here
- return nil
-}