This commit is contained in:
Solomon Hykes 2013-02-13 14:59:24 -08:00
commit 2d5a1abf79
6 changed files with 117 additions and 55 deletions

View File

@ -16,6 +16,12 @@ import (
"time"
)
var sysInitPath string
func init() {
sysInitPath = SelfPath()
}
type Container struct {
Id string
Root string
@ -29,6 +35,7 @@ type Container struct {
Filesystem *Filesystem
State *State
SysInitPath string
lxcConfigPath string
cmd *exec.Cmd
stdout *writeBroadcaster
@ -58,6 +65,7 @@ func createContainer(id string, root string, command string, args []string, laye
Filesystem: newFilesystem(path.Join(root, "rootfs"), path.Join(root, "rw"), layers),
State: newState(),
SysInitPath: sysInitPath,
lxcConfigPath: path.Join(root, "config.lxc"),
stdout: newWriteBroadcaster(),
stderr: newWriteBroadcaster(),
@ -261,6 +269,7 @@ func (container *Container) Start() error {
"-n", container.Id,
"-f", container.lxcConfigPath,
"--",
"/sbin/init",
container.Path,
}
params = append(params, container.Args...)

View File

@ -6,6 +6,13 @@ import (
"testing"
)
// Hack to run sys init during unit testing
func init() {
if SelfPath() == "/sbin/init" {
SysInit()
}
}
func newTestDocker() (*Docker, error) {
root, err := ioutil.TempDir("", "docker-test")
if err != nil {

View File

@ -1,26 +1,26 @@
package main
import (
"github.com/dotcloud/docker"
"github.com/dotcloud/docker/rcli"
"github.com/dotcloud/docker/image"
"github.com/dotcloud/docker/future"
"bufio"
"bytes"
"encoding/json"
"errors"
"log"
"io"
"flag"
"fmt"
"strings"
"text/tabwriter"
"os"
"time"
"github.com/dotcloud/docker"
"github.com/dotcloud/docker/future"
"github.com/dotcloud/docker/image"
"github.com/dotcloud/docker/rcli"
"io"
"log"
"net/http"
"encoding/json"
"bytes"
"sync"
"net/url"
"os"
"path"
"strings"
"sync"
"text/tabwriter"
"time"
)
const VERSION = "0.0.1"
@ -176,7 +176,6 @@ func (srv *Server) CmdWrite(stdin io.ReadCloser, stdout io.Writer, args ...strin
return errors.New("No such container: " + name)
}
func (srv *Server) CmdLs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
cmd := rcli.Subcmd(stdout, "ls", "[OPTIONS] CONTAINER PATH", "List the contents of a container's directory")
if err := cmd.Parse(args); err != nil {
@ -268,7 +267,7 @@ func (srv *Server) CmdRm(stdin io.ReadCloser, stdout io.Writer, args ...string)
return errors.New("No such container: " + name)
}
if err := srv.containers.Destroy(container); err != nil {
fmt.Fprintln(stdout, "Error destroying container " + name + ": " + err.Error())
fmt.Fprintln(stdout, "Error destroying container "+name+": "+err.Error())
}
}
return nil
@ -286,7 +285,7 @@ func (srv *Server) CmdKill(stdin io.ReadCloser, stdout io.Writer, args ...string
return errors.New("No such container: " + name)
}
if err := container.Kill(); err != nil {
fmt.Fprintln(stdout, "Error killing container " + name + ": " + err.Error())
fmt.Fprintln(stdout, "Error killing container "+name+": "+err.Error())
}
}
return nil
@ -373,7 +372,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
nameFilter = cmd.Arg(0)
}
w := tabwriter.NewWriter(stdout, 20, 1, 3, ' ', 0)
if (!*quiet) {
if !*quiet {
fmt.Fprintf(w, "NAME\tID\tCREATED\tPARENT\n")
}
for _, name := range srv.images.Names() {
@ -390,10 +389,10 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
id += "..."
}
for idx, field := range []string{
/* NAME */ name,
/* ID */ id,
/* CREATED */ future.HumanDuration(time.Now().Sub(img.Created)) + " ago",
/* PARENT */ img.Parent,
/* NAME */ name,
/* ID */ id,
/* CREATED */ future.HumanDuration(time.Now().Sub(img.Created)) + " ago",
/* PARENT */ img.Parent,
} {
if idx == 0 {
w.Write([]byte(field))
@ -407,7 +406,7 @@ func (srv *Server) CmdImages(stdin io.ReadCloser, stdout io.Writer, args ...stri
}
}
}
if (!*quiet) {
if !*quiet {
w.Flush()
}
return nil
@ -424,7 +423,7 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
return nil
}
w := tabwriter.NewWriter(stdout, 12, 1, 3, ' ', 0)
if (!*quiet) {
if !*quiet {
fmt.Fprintf(w, "ID\tIMAGE\tCOMMAND\tCREATED\tSTATUS\tCOMMENT\n")
}
for _, container := range srv.containers.List() {
@ -437,13 +436,13 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
if !*fl_full {
command = docker.Trunc(command, 20)
}
for idx, field := range[]string {
/* ID */ container.Id,
/* IMAGE */ container.GetUserData("image"),
/* COMMAND */ command,
/* CREATED */ future.HumanDuration(time.Now().Sub(container.Created)) + " ago",
/* STATUS */ container.State.String(),
/* COMMENT */ comment,
for idx, field := range []string{
/* ID */ container.Id,
/* IMAGE */ container.GetUserData("image"),
/* COMMAND */ command,
/* CREATED */ future.HumanDuration(time.Now().Sub(container.Created)) + " ago",
/* STATUS */ container.State.String(),
/* COMMENT */ comment,
} {
if idx == 0 {
w.Write([]byte(field))
@ -456,7 +455,7 @@ func (srv *Server) CmdPs(stdin io.ReadCloser, stdout io.Writer, args ...string)
stdout.Write([]byte(container.Id + "\n"))
}
}
if (!*quiet) {
if !*quiet {
w.Flush()
}
return nil
@ -475,7 +474,6 @@ func (srv *Server) CmdLayers(stdin io.ReadCloser, stdout io.Writer, args ...stri
return nil
}
func (srv *Server) CmdCp(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
cmd := rcli.Subcmd(stdout,
"cp", "[OPTIONS] IMAGE NAME",
@ -521,7 +519,6 @@ func (srv *Server) CmdCommit(stdin io.ReadCloser, stdout io.Writer, args ...stri
return errors.New("No such container: " + containerName)
}
func (srv *Server) CmdTar(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
cmd := rcli.Subcmd(stdout,
"tar", "CONTAINER",
@ -592,7 +589,6 @@ func (srv *Server) CmdReset(stdin io.ReadCloser, stdout io.Writer, args ...strin
return nil
}
func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string) error {
cmd := rcli.Subcmd(stdout, "logs", "[OPTIONS] CONTAINER", "Fetch the logs of a container")
if err := cmd.Parse(args); err != nil {
@ -615,7 +611,6 @@ func (srv *Server) CmdLogs(stdin io.ReadCloser, stdout io.Writer, args ...string
return errors.New("No such container: " + cmd.Arg(0))
}
func (srv *Server) CreateContainer(img *image.Image, tty bool, openStdin bool, comment string, cmd string, args ...string) (*docker.Container, error) {
id := future.RandomId()[:8]
container, err := srv.containers.Create(id, cmd, args, img.Layers,
@ -658,7 +653,7 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
return err
}
wg.Add(1)
go func() { io.Copy(c_stdin, stdin); wg.Add(-1); }()
go func() { io.Copy(c_stdin, stdin); wg.Add(-1) }()
}
if *fl_o {
c_stdout, err := container.StdoutPipe()
@ -666,7 +661,7 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
return err
}
wg.Add(1)
go func() { io.Copy(stdout, c_stdout); wg.Add(-1); }()
go func() { io.Copy(stdout, c_stdout); wg.Add(-1) }()
}
if *fl_e {
c_stderr, err := container.StderrPipe()
@ -674,7 +669,7 @@ func (srv *Server) CmdAttach(stdin io.ReadCloser, stdout io.Writer, args ...stri
return err
}
wg.Add(1)
go func() { io.Copy(stdout, c_stderr); wg.Add(-1); }()
go func() { io.Copy(stdout, c_stderr); wg.Add(-1) }()
}
wg.Wait()
return nil
@ -690,7 +685,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
return nil
}
name := cmd.Arg(0)
var cmdline[]string
var cmdline []string
if len(cmd.Args()) >= 2 {
cmdline = cmd.Args()[1:]
}
@ -723,7 +718,7 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
if *fl_attach {
future.Go(func() error {
log.Printf("CmdRun(): start receiving stdin\n")
_, err := io.Copy(cmd_stdin, stdin);
_, err := io.Copy(cmd_stdin, stdin)
log.Printf("CmdRun(): done receiving stdin\n")
cmd_stdin.Close()
return err
@ -744,11 +739,11 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
return err
}
sending_stdout := future.Go(func() error {
_, err := io.Copy(stdout, cmd_stdout);
_, err := io.Copy(stdout, cmd_stdout)
return err
})
sending_stderr := future.Go(func() error {
_, err := io.Copy(stdout, cmd_stderr);
_, err := io.Copy(stdout, cmd_stderr)
return err
})
err_sending_stdout := <-sending_stdout
@ -770,6 +765,11 @@ func (srv *Server) CmdRun(stdin io.ReadCloser, stdout io.Writer, args ...string)
}
func main() {
if docker.SelfPath() == "/sbin/init" {
// Running in init mode
docker.SysInit()
return
}
future.Seed()
flag.Parse()
d, err := New()
@ -800,7 +800,7 @@ func New() (*Server, error) {
return nil, err
}
srv := &Server{
images: images,
images: images,
containers: containers,
}
return srv, nil
@ -845,9 +845,7 @@ func (srv *Server) CmdWeb(stdin io.ReadCloser, stdout io.Writer, args ...string)
return nil
}
type Server struct {
containers *docker.Docker
images *image.Store
containers *docker.Docker
images *image.Store
}

View File

@ -22,7 +22,8 @@ lxc.utsname = {{.Id}}
#lxc.network.ipv4 = {ip_address}/{ip_prefix_len}
# root filesystem
lxc.rootfs = {{.Filesystem.RootFS}}
{{$ROOTFS := .Filesystem.RootFS}}
lxc.rootfs = {{$ROOTFS}}
# use a dedicated pts for the container (and limit the number of pseudo terminal
# available)
@ -66,15 +67,18 @@ lxc.cgroup.devices.allow = c 10:200 rwm
# standard mount point
lxc.mount.entry = proc {{.Filesystem.RootFS}}/proc proc nosuid,nodev,noexec 0 0
lxc.mount.entry = sysfs {{.Filesystem.RootFS}}/sys sysfs nosuid,nodev,noexec 0 0
lxc.mount.entry = devpts {{.Filesystem.RootFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
#lxc.mount.entry = varrun {{.Filesystem.RootFS}}/var/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0
#lxc.mount.entry = varlock {{.Filesystem.RootFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
#lxc.mount.entry = shm {{.Filesystem.RootFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
lxc.mount.entry = proc {{$ROOTFS}}/proc proc nosuid,nodev,noexec 0 0
lxc.mount.entry = sysfs {{$ROOTFS}}/sys sysfs nosuid,nodev,noexec 0 0
lxc.mount.entry = devpts {{$ROOTFS}}/dev/pts devpts newinstance,ptmxmode=0666,nosuid,noexec 0 0
#lxc.mount.entry = varrun {{$ROOTFS}}/var/run tmpfs mode=755,size=4096k,nosuid,nodev,noexec 0 0
#lxc.mount.entry = varlock {{$ROOTFS}}/var/lock tmpfs size=1024k,nosuid,nodev,noexec 0 0
#lxc.mount.entry = shm {{$ROOTFS}}/dev/shm tmpfs size=65536k,nosuid,nodev,noexec 0 0
# Inject docker-init
lxc.mount.entry = {{.SysInitPath}} {{$ROOTFS}}/sbin/init none bind,ro 0 0
# In order to get a working DNS environment, mount bind (ro) the host's /etc/resolv.conf into the container
lxc.mount.entry = /etc/resolv.conf {{.Filesystem.RootFS}}/etc/resolv.conf none bind,ro 0 0
lxc.mount.entry = /etc/resolv.conf {{$ROOTFS}}/etc/resolv.conf none bind,ro 0 0
# drop linux capabilities (apply mainly to the user root in the container)

29
sysinit.go Normal file
View File

@ -0,0 +1,29 @@
package docker
import (
"fmt"
"log"
"os"
"os/exec"
"syscall"
)
// Sys Init code
// This code is run INSIDE the container and is responsible for setting
// up the environment before running the actual process
func SysInit() {
if len(os.Args) <= 1 {
fmt.Println("You should not invoke docker-init manually")
os.Exit(1)
}
path, err := exec.LookPath(os.Args[1])
if err != nil {
log.Printf("Unable to locate %v", os.Args[1])
os.Exit(127)
}
if err := syscall.Exec(path, os.Args[1:], os.Environ()); err != nil {
panic(err)
}
}

View File

@ -4,7 +4,9 @@ import (
"bytes"
"container/list"
"io"
"os"
"os/exec"
"path/filepath"
"sync"
)
@ -34,6 +36,19 @@ func Tar(path string) (io.Reader, error) {
return output, nil
}
// Figure out the absolute path of our own binary
func SelfPath() string {
path, err := exec.LookPath(os.Args[0])
if err != nil {
panic(err)
}
path, err = filepath.Abs(path)
if err != nil {
panic(err)
}
return path
}
type nopWriteCloser struct {
io.Writer
}