Merge pull request #9113 from Azure/windows-client

Windows port of Docker Client
This commit is contained in:
Tibor Vass 2014-11-15 10:40:31 -08:00
commit 08201d021e
41 changed files with 588 additions and 166 deletions

1
.gitignore vendored
View file

@ -4,6 +4,7 @@
.vagrant*
bin
docker/docker
*.exe
.*.swp
a.out
*.orig

View file

@ -68,7 +68,8 @@ RUN cd /usr/local/go/src && ./make.bash --no-clean 2>&1
ENV DOCKER_CROSSPLATFORMS \
linux/386 linux/arm \
darwin/amd64 darwin/386 \
freebsd/amd64 freebsd/386 freebsd/arm
freebsd/amd64 freebsd/386 freebsd/arm \
windows/amd64 windows/386
# (set an explicit GOARM of 5 for maximum compatibility)
ENV GOARM 5
RUN cd /usr/local/go/src && bash -xc 'for platform in $DOCKER_CROSSPLATFORMS; do GOOS=${platform%/*} GOARCH=${platform##*/} ./make.bash --no-clean 2>&1; done'

View file

@ -18,7 +18,6 @@ import (
"runtime"
"strconv"
"strings"
"syscall"
"text/tabwriter"
"text/template"
"time"
@ -608,7 +607,7 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
signal.CatchAll(sigc)
go func() {
for s := range sigc {
if s == syscall.SIGCHLD {
if s == signal.SIGCHLD {
continue
}
var sig string
@ -619,7 +618,7 @@ func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
}
}
if sig == "" {
log.Errorf("Unsupported signal: %d. Discarding.", s)
log.Errorf("Unsupported signal: %v. Discarding.", s)
}
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
log.Debugf("Error sending signal: %s", err)
@ -2184,7 +2183,7 @@ func (cli *DockerCli) CmdCreate(args ...string) error {
flName = cmd.String([]string{"-name"}, "", "Assign a name to the container")
)
config, hostConfig, cmd, err := runconfig.Parse(cmd, args, nil)
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
if err != nil {
return err
}
@ -2220,7 +2219,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
ErrConflictDetachAutoRemove = fmt.Errorf("Conflicting options: --rm and -d")
)
config, hostConfig, cmd, err := runconfig.Parse(cmd, args, nil)
config, hostConfig, cmd, err := runconfig.Parse(cmd, args)
if err != nil {
return err
}

View file

@ -14,12 +14,12 @@ import (
gosignal "os/signal"
"strconv"
"strings"
"syscall"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/engine"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/registry"
@ -238,7 +238,7 @@ func (cli *DockerCli) monitorTtySize(id string, isExec bool) error {
cli.resizeTty(id, isExec)
sigchan := make(chan os.Signal, 1)
gosignal.Notify(sigchan, syscall.SIGWINCH)
gosignal.Notify(sigchan, signal.SIGWINCH)
go func() {
for _ = range sigchan {
cli.resizeTty(id, isExec)

View file

@ -183,7 +183,7 @@ func run(b *Builder, args []string, attributes map[string]bool, original string)
runCmd.SetOutput(ioutil.Discard)
runCmd.Usage = nil
config, _, _, err := runconfig.Parse(runCmd, append([]string{b.image}, args...), nil)
config, _, _, err := runconfig.Parse(runCmd, append([]string{b.image}, args...))
if err != nil {
return err
}

View file

@ -1,3 +1,5 @@
// +build daemon
package graphdriver
import (

View file

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"runtime"
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
@ -16,10 +17,17 @@ var (
func init() {
if dockerCertPath == "" {
dockerCertPath = filepath.Join(os.Getenv("HOME"), ".docker")
dockerCertPath = filepath.Join(getHomeDir(), ".docker")
}
}
func getHomeDir() string {
if runtime.GOOS == "windows" {
return os.Getenv("USERPROFILE")
}
return os.Getenv("HOME")
}
var (
flVersion = flag.Bool([]string{"v", "-version"}, false, "Print version information and quit")
flDaemon = flag.Bool([]string{"d", "-daemon"}, false, "Enable daemon mode")

View file

@ -661,7 +661,7 @@ func TestDefaultContainerName(t *testing.T) {
daemon := mkDaemonFromEngine(eng, t)
defer nuke(daemon)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"}, nil)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
if err != nil {
t.Fatal(err)
}
@ -685,7 +685,7 @@ func TestRandomContainerName(t *testing.T) {
daemon := mkDaemonFromEngine(eng, t)
defer nuke(daemon)
config, _, _, err := parseRun([]string{GetTestImage(daemon).ID, "echo test"}, nil)
config, _, _, err := parseRun([]string{GetTestImage(daemon).ID, "echo test"})
if err != nil {
t.Fatal(err)
}
@ -716,7 +716,7 @@ func TestContainerNameValidation(t *testing.T) {
{"abc-123_AAA.1", true},
{"\000asdf", false},
} {
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"}, nil)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
if err != nil {
if !test.Valid {
continue
@ -757,7 +757,7 @@ func TestLinkChildContainer(t *testing.T) {
daemon := mkDaemonFromEngine(eng, t)
defer nuke(daemon)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"}, nil)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
if err != nil {
t.Fatal(err)
}
@ -773,7 +773,7 @@ func TestLinkChildContainer(t *testing.T) {
t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
}
config, _, _, err = parseRun([]string{GetTestImage(daemon).ID, "echo test"}, nil)
config, _, _, err = parseRun([]string{GetTestImage(daemon).ID, "echo test"})
if err != nil {
t.Fatal(err)
}
@ -799,7 +799,7 @@ func TestGetAllChildren(t *testing.T) {
daemon := mkDaemonFromEngine(eng, t)
defer nuke(daemon)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"}, nil)
config, _, _, err := parseRun([]string{unitTestImageID, "echo test"})
if err != nil {
t.Fatal(err)
}
@ -815,7 +815,7 @@ func TestGetAllChildren(t *testing.T) {
t.Fatalf("Expect webapp id to match container id: %s != %s", webapp.ID, container.ID)
}
config, _, _, err = parseRun([]string{unitTestImageID, "echo test"}, nil)
config, _, _, err = parseRun([]string{unitTestImageID, "echo test"})
if err != nil {
t.Fatal(err)
}

View file

@ -12,7 +12,7 @@ func TestCreateNumberHostname(t *testing.T) {
eng := NewTestEngine(t)
defer mkDaemonFromEngine(eng, t).Nuke()
config, _, _, err := parseRun([]string{"-h", "web.0", unitTestImageID, "echo test"}, nil)
config, _, _, err := parseRun([]string{"-h", "web.0", unitTestImageID, "echo test"})
if err != nil {
t.Fatal(err)
}
@ -24,7 +24,7 @@ func TestCommit(t *testing.T) {
eng := NewTestEngine(t)
defer mkDaemonFromEngine(eng, t).Nuke()
config, _, _, err := parseRun([]string{unitTestImageID, "/bin/cat"}, nil)
config, _, _, err := parseRun([]string{unitTestImageID, "/bin/cat"})
if err != nil {
t.Fatal(err)
}
@ -48,7 +48,7 @@ func TestMergeConfigOnCommit(t *testing.T) {
container1, _, _ := mkContainer(runtime, []string{"-e", "FOO=bar", unitTestImageID, "echo test > /tmp/foo"}, t)
defer runtime.Destroy(container1)
config, _, _, err := parseRun([]string{container1.ID, "cat /tmp/foo"}, nil)
config, _, _, err := parseRun([]string{container1.ID, "cat /tmp/foo"})
if err != nil {
t.Error(err)
}
@ -102,7 +102,7 @@ func TestRestartKillWait(t *testing.T) {
runtime := mkDaemonFromEngine(eng, t)
defer runtime.Nuke()
config, hostConfig, _, err := parseRun([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
config, hostConfig, _, err := parseRun([]string{"-i", unitTestImageID, "/bin/cat"})
if err != nil {
t.Fatal(err)
}
@ -163,7 +163,7 @@ func TestCreateStartRestartStopStartKillRm(t *testing.T) {
eng := NewTestEngine(t)
defer mkDaemonFromEngine(eng, t).Nuke()
config, hostConfig, _, err := parseRun([]string{"-i", unitTestImageID, "/bin/cat"}, nil)
config, hostConfig, _, err := parseRun([]string{"-i", unitTestImageID, "/bin/cat"})
if err != nil {
t.Fatal(err)
}

View file

@ -19,7 +19,6 @@ import (
"github.com/docker/docker/daemon"
"github.com/docker/docker/engine"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/runconfig"
"github.com/docker/docker/utils"
)
@ -250,7 +249,7 @@ func readFile(src string, t *testing.T) (content string) {
// The caller is responsible for destroying the container.
// Call t.Fatal() at the first error.
func mkContainer(r *daemon.Daemon, args []string, t *testing.T) (*daemon.Container, *runconfig.HostConfig, error) {
config, hc, _, err := parseRun(args, nil)
config, hc, _, err := parseRun(args)
defer func() {
if err != nil && t != nil {
t.Fatal(err)
@ -351,9 +350,9 @@ func getImages(eng *engine.Engine, t *testing.T, all bool, filter string) *engin
}
func parseRun(args []string, sysInfo *sysinfo.SysInfo) (*runconfig.Config, *runconfig.HostConfig, *flag.FlagSet, error) {
func parseRun(args []string) (*runconfig.Config, *runconfig.HostConfig, *flag.FlagSet, error) {
cmd := flag.NewFlagSet("run", flag.ContinueOnError)
cmd.SetOutput(ioutil.Discard)
cmd.Usage = nil
return runconfig.Parse(cmd, args, sysInfo)
return runconfig.Parse(cmd, args)
}

View file

@ -5,7 +5,7 @@ import (
"net"
"net/url"
"os"
"path/filepath"
"path"
"regexp"
"strings"
@ -151,13 +151,13 @@ func ValidatePath(val string) (string, error) {
splited := strings.SplitN(val, ":", 2)
if len(splited) == 1 {
containerPath = splited[0]
val = filepath.Clean(splited[0])
val = path.Clean(splited[0])
} else {
containerPath = splited[1]
val = fmt.Sprintf("%s:%s", splited[0], filepath.Clean(splited[1]))
val = fmt.Sprintf("%s:%s", splited[0], path.Clean(splited[1]))
}
if !filepath.IsAbs(containerPath) {
if !path.IsAbs(containerPath) {
return val, fmt.Errorf("%s is not an absolute path", containerPath)
}
return val, nil

View file

@ -192,20 +192,11 @@ func (ta *tarAppender) addTarFile(path, name string) error {
hdr.Name = name
var (
nlink uint32
inode uint64
)
if stat, ok := fi.Sys().(*syscall.Stat_t); ok {
nlink = uint32(stat.Nlink)
inode = uint64(stat.Ino)
// Currently go does not fill in the major/minors
if stat.Mode&syscall.S_IFBLK == syscall.S_IFBLK ||
stat.Mode&syscall.S_IFCHR == syscall.S_IFCHR {
hdr.Devmajor = int64(major(uint64(stat.Rdev)))
hdr.Devminor = int64(minor(uint64(stat.Rdev)))
}
nlink, inode, err := setHeaderForSpecialDevice(hdr, ta, name, fi.Sys())
if err != nil {
return err
}
// if it's a regular file and has more than 1 link,
// it's hardlinked, so set the type flag accordingly
if fi.Mode().IsRegular() && nlink > 1 {
@ -291,7 +282,7 @@ func createTarFile(path, extractDir string, hdr *tar.Header, reader io.Reader, L
mode |= syscall.S_IFIFO
}
if err := syscall.Mknod(path, mode, int(mkdev(hdr.Devmajor, hdr.Devminor))); err != nil {
if err := system.Mknod(path, mode, int(system.Mkdev(hdr.Devmajor, hdr.Devminor))); err != nil {
return err
}

View file

@ -0,0 +1,39 @@
// +build !windows
package archive
import (
"errors"
"syscall"
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
)
func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, stat interface{}) (nlink uint32, inode uint64, err error) {
s, ok := stat.(*syscall.Stat_t)
if !ok {
err = errors.New("cannot convert stat value to syscall.Stat_t")
return
}
nlink = uint32(s.Nlink)
inode = uint64(s.Ino)
// Currently go does not fil in the major/minors
if s.Mode&syscall.S_IFBLK == syscall.S_IFBLK ||
s.Mode&syscall.S_IFCHR == syscall.S_IFCHR {
hdr.Devmajor = int64(major(uint64(s.Rdev)))
hdr.Devminor = int64(minor(uint64(s.Rdev)))
}
return
}
func major(device uint64) uint64 {
return (device >> 8) & 0xfff
}
func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}

View file

@ -0,0 +1,12 @@
// +build windows
package archive
import (
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
)
func setHeaderForSpecialDevice(hdr *tar.Header, ta *tarAppender, name string, stat interface{}) (nlink uint32, inode uint64, err error) {
// do nothing. no notion of Rdev, Inode, Nlink in stat on Windows
return
}

View file

@ -135,7 +135,7 @@ func Changes(layers []string, rw string) ([]Change, error) {
type FileInfo struct {
parent *FileInfo
name string
stat syscall.Stat_t
stat *system.Stat
children map[string]*FileInfo
capability []byte
added bool
@ -168,7 +168,7 @@ func (info *FileInfo) path() string {
}
func (info *FileInfo) isDir() bool {
return info.parent == nil || info.stat.Mode&syscall.S_IFDIR == syscall.S_IFDIR
return info.parent == nil || info.stat.Mode()&syscall.S_IFDIR == syscall.S_IFDIR
}
func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
@ -199,21 +199,21 @@ func (info *FileInfo) addChanges(oldInfo *FileInfo, changes *[]Change) {
oldChild, _ := oldChildren[name]
if oldChild != nil {
// change?
oldStat := &oldChild.stat
newStat := &newChild.stat
oldStat := oldChild.stat
newStat := newChild.stat
// Note: We can't compare inode or ctime or blocksize here, because these change
// when copying a file into a container. However, that is not generally a problem
// because any content change will change mtime, and any status change should
// be visible when actually comparing the stat fields. The only time this
// breaks down is if some code intentionally hides a change by setting
// back mtime
if oldStat.Mode != newStat.Mode ||
oldStat.Uid != newStat.Uid ||
oldStat.Gid != newStat.Gid ||
oldStat.Rdev != newStat.Rdev ||
if oldStat.Mode() != newStat.Mode() ||
oldStat.Uid() != newStat.Uid() ||
oldStat.Gid() != newStat.Gid() ||
oldStat.Rdev() != newStat.Rdev() ||
// Don't look at size for dirs, its not a good measure of change
(oldStat.Size != newStat.Size && oldStat.Mode&syscall.S_IFDIR != syscall.S_IFDIR) ||
!sameFsTimeSpec(system.GetLastModification(oldStat), system.GetLastModification(newStat)) ||
(oldStat.Size() != newStat.Size() && oldStat.Mode()&syscall.S_IFDIR != syscall.S_IFDIR) ||
!sameFsTimeSpec(oldStat.Mtim(), newStat.Mtim()) ||
bytes.Compare(oldChild.capability, newChild.capability) != 0 {
change := Change{
Path: newChild.path(),
@ -299,9 +299,11 @@ func collectFileInfo(sourceDir string) (*FileInfo, error) {
parent: parent,
}
if err := syscall.Lstat(path, &info.stat); err != nil {
s, err := system.Lstat(path)
if err != nil {
return err
}
info.stat = s
info.capability, _ = system.Lgetxattr(path, "security.capability")
@ -359,14 +361,6 @@ func ChangesSize(newDir string, changes []Change) int64 {
return size
}
func major(device uint64) uint64 {
return (device >> 8) & 0xfff
}
func minor(device uint64) uint64 {
return (device & 0xff) | ((device >> 12) & 0xfff00)
}
// ExportChanges produces an Archive from the provided changes, relative to dir.
func ExportChanges(dir string, changes []Change) (Archive, error) {
reader, writer := io.Pipe()

View file

@ -12,23 +12,21 @@ import (
"github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
"github.com/docker/docker/pkg/pools"
"github.com/docker/docker/pkg/system"
)
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major,
// then the top 12 bits of the minor
func mkdev(major int64, minor int64) uint32 {
return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
}
// ApplyLayer parses a diff in the standard layer format from `layer`, and
// applies it to the directory `dest`.
func ApplyLayer(dest string, layer ArchiveReader) error {
// We need to be able to set any perms
oldmask := syscall.Umask(0)
defer syscall.Umask(oldmask)
oldmask, err := system.Umask(0)
if err != nil {
return err
}
layer, err := DecompressStream(layer)
defer system.Umask(oldmask) // ignore err, ErrNotSupportedPlatform
layer, err = DecompressStream(layer)
if err != nil {
return err
}

12
pkg/signal/signal_unix.go Normal file
View file

@ -0,0 +1,12 @@
// +build !windows
package signal
import (
"syscall"
)
// Signals used in api/client (no windows equivalent, use
// invalid signals so they don't get handled)
const SIGCHLD = syscall.SIGCHLD
const SIGWINCH = syscall.SIGWINCH

View file

@ -0,0 +1,12 @@
// +build windows
package signal
import (
"syscall"
)
// Signals used in api/client (no windows equivalent, use
// invalid signals so they don't get handled)
const SIGCHLD = syscall.Signal(0xff)
const SIGWINCH = syscall.Signal(0xff)

16
pkg/system/lstat.go Normal file
View file

@ -0,0 +1,16 @@
// +build !windows
package system
import (
"syscall"
)
func Lstat(path string) (*Stat, error) {
s := &syscall.Stat_t{}
err := syscall.Lstat(path, s)
if err != nil {
return nil, err
}
return fromStatT(s)
}

25
pkg/system/lstat_test.go Normal file
View file

@ -0,0 +1,25 @@
package system
import (
"testing"
)
func TestLstat(t *testing.T) {
file, invalid, _ := prepareFiles(t)
statFile, err := Lstat(file)
if err != nil {
t.Fatal(err)
}
if statFile == nil {
t.Fatal("returned empty stat for existing file")
}
statInvalid, err := Lstat(invalid)
if err == nil {
t.Fatal("did not return error for non-existing file")
}
if statInvalid != nil {
t.Fatal("returned non-nil stat for non-existing file")
}
}

View file

@ -0,0 +1,8 @@
// +build windows
package system
func Lstat(path string) (*Stat, error) {
// should not be called on cli code path
return nil, ErrNotSupportedPlatform
}

18
pkg/system/mknod.go Normal file
View file

@ -0,0 +1,18 @@
// +build !windows
package system
import (
"syscall"
)
func Mknod(path string, mode uint32, dev int) error {
return syscall.Mknod(path, mode, dev)
}
// Linux device nodes are a bit weird due to backwards compat with 16 bit device nodes.
// They are, from low to high: the lower 8 bits of the minor, then 12 bits of the major,
// then the top 12 bits of the minor
func Mkdev(major int64, minor int64) uint32 {
return uint32(((minor & 0xfff00) << 12) | ((major & 0xfff) << 8) | (minor & 0xff))
}

View file

@ -0,0 +1,12 @@
// +build windows
package system
func Mknod(path string, mode uint32, dev int) error {
// should not be called on cli code path
return ErrNotSupportedPlatform
}
func Mkdev(major int64, minor int64) uint32 {
panic("Mkdev not implemented on windows, should not be called on cli code")
}

42
pkg/system/stat.go Normal file
View file

@ -0,0 +1,42 @@
package system
import (
"syscall"
)
type Stat struct {
mode uint32
uid uint32
gid uint32
rdev uint64
size int64
mtim syscall.Timespec
}
func (s Stat) Mode() uint32 {
return s.mode
}
func (s Stat) Uid() uint32 {
return s.uid
}
func (s Stat) Gid() uint32 {
return s.gid
}
func (s Stat) Rdev() uint64 {
return s.rdev
}
func (s Stat) Size() int64 {
return s.size
}
func (s Stat) Mtim() syscall.Timespec {
return s.mtim
}
func (s Stat) GetLastModification() syscall.Timespec {
return s.Mtim()
}

View file

@ -4,10 +4,11 @@ import (
"syscall"
)
func GetLastAccess(stat *syscall.Stat_t) syscall.Timespec {
return stat.Atim
}
func GetLastModification(stat *syscall.Stat_t) syscall.Timespec {
return stat.Mtim
func fromStatT(s *syscall.Stat_t) (*Stat, error) {
return &Stat{size: s.Size,
mode: s.Mode,
uid: s.Uid,
gid: s.Gid,
rdev: s.Rdev,
mtim: s.Mtim}, nil
}

34
pkg/system/stat_test.go Normal file
View file

@ -0,0 +1,34 @@
package system
import (
"syscall"
"testing"
)
func TestFromStatT(t *testing.T) {
file, _, _ := prepareFiles(t)
stat := &syscall.Stat_t{}
err := syscall.Lstat(file, stat)
s, err := fromStatT(stat)
if err != nil {
t.Fatal(err)
}
if stat.Mode != s.Mode() {
t.Fatal("got invalid mode")
}
if stat.Uid != s.Uid() {
t.Fatal("got invalid uid")
}
if stat.Gid != s.Gid() {
t.Fatal("got invalid gid")
}
if stat.Rdev != s.Rdev() {
t.Fatal("got invalid rdev")
}
if stat.Mtim != s.Mtim() {
t.Fatal("got invalid mtim")
}
}

View file

@ -1,13 +1,16 @@
// +build !linux
// +build !linux,!windows
package system
import "syscall"
import (
"syscall"
)
func GetLastAccess(stat *syscall.Stat_t) syscall.Timespec {
return stat.Atimespec
}
func GetLastModification(stat *syscall.Stat_t) syscall.Timespec {
return stat.Mtimespec
func fromStatT(s *syscall.Stat_t) (*Stat, error) {
return &Stat{size: s.Size,
mode: uint32(s.Mode),
uid: s.Uid,
gid: s.Gid,
rdev: uint64(s.Rdev),
mtim: s.Mtimespec}, nil
}

View file

@ -0,0 +1,12 @@
// +build windows
package system
import (
"errors"
"syscall"
)
func fromStatT(s *syscall.Win32FileAttributeData) (*Stat, error) {
return nil, errors.New("fromStatT should not be called on windows path")
}

11
pkg/system/umask.go Normal file
View file

@ -0,0 +1,11 @@
// +build !windows
package system
import (
"syscall"
)
func Umask(newmask int) (oldmask int, err error) {
return syscall.Umask(newmask), nil
}

View file

@ -0,0 +1,8 @@
// +build windows
package system
func Umask(newmask int) (oldmask int, err error) {
// should not be called on cli code path
return 0, ErrNotSupportedPlatform
}

View file

@ -0,0 +1,87 @@
// +build windows
package term
import (
"syscall"
"unsafe"
)
const (
// Consts for Get/SetConsoleMode function
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683167(v=vs.85).aspx
ENABLE_ECHO_INPUT = 0x0004
ENABLE_INSERT_MODE = 0x0020
ENABLE_LINE_INPUT = 0x0002
ENABLE_MOUSE_INPUT = 0x0010
ENABLE_PROCESSED_INPUT = 0x0001
ENABLE_QUICK_EDIT_MODE = 0x0040
ENABLE_WINDOW_INPUT = 0x0008
// If parameter is a screen buffer handle, additional values
ENABLE_PROCESSED_OUTPUT = 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT = 0x0002
)
var kernel32DLL = syscall.NewLazyDLL("kernel32.dll")
var (
setConsoleModeProc = kernel32DLL.NewProc("SetConsoleMode")
getConsoleScreenBufferInfoProc = kernel32DLL.NewProc("GetConsoleScreenBufferInfo")
)
func GetConsoleMode(fileDesc uintptr) (uint32, error) {
var mode uint32
err := syscall.GetConsoleMode(syscall.Handle(fileDesc), &mode)
return mode, err
}
func SetConsoleMode(fileDesc uintptr, mode uint32) error {
r, _, err := setConsoleModeProc.Call(fileDesc, uintptr(mode), 0)
if r == 0 {
if err != nil {
return err
}
return syscall.EINVAL
}
return nil
}
// types for calling GetConsoleScreenBufferInfo
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms682093(v=vs.85).aspx
type (
SHORT int16
SMALL_RECT struct {
Left SHORT
Top SHORT
Right SHORT
Bottom SHORT
}
COORD struct {
X SHORT
Y SHORT
}
WORD uint16
CONSOLE_SCREEN_BUFFER_INFO struct {
dwSize COORD
dwCursorPosition COORD
wAttributes WORD
srWindow SMALL_RECT
dwMaximumWindowSize COORD
}
)
func GetConsoleScreenBufferInfo(fileDesc uintptr) (*CONSOLE_SCREEN_BUFFER_INFO, error) {
var info CONSOLE_SCREEN_BUFFER_INFO
r, _, err := getConsoleScreenBufferInfoProc.Call(uintptr(fileDesc), uintptr(unsafe.Pointer(&info)), 0)
if r == 0 {
if err != nil {
return nil, err
}
return nil, syscall.EINVAL
}
return &info, nil
}

View file

@ -1,3 +1,5 @@
// +build !windows
package term
import (

89
pkg/term/term_windows.go Normal file
View file

@ -0,0 +1,89 @@
// +build windows
package term
type State struct {
mode uint32
}
type Winsize struct {
Height uint16
Width uint16
x uint16
y uint16
}
func GetWinsize(fd uintptr) (*Winsize, error) {
ws := &Winsize{}
var info *CONSOLE_SCREEN_BUFFER_INFO
info, err := GetConsoleScreenBufferInfo(fd)
if err != nil {
return nil, err
}
ws.Height = uint16(info.srWindow.Right - info.srWindow.Left + 1)
ws.Width = uint16(info.srWindow.Bottom - info.srWindow.Top + 1)
ws.x = 0 // todo azlinux -- this is the pixel size of the Window, and not currently used by any caller
ws.y = 0
return ws, nil
}
func SetWinsize(fd uintptr, ws *Winsize) error {
return nil
}
// IsTerminal returns true if the given file descriptor is a terminal.
func IsTerminal(fd uintptr) bool {
_, e := GetConsoleMode(fd)
return e == nil
}
// Restore restores the terminal connected to the given file descriptor to a
// previous state.
func RestoreTerminal(fd uintptr, state *State) error {
return SetConsoleMode(fd, state.mode)
}
func SaveState(fd uintptr) (*State, error) {
mode, e := GetConsoleMode(fd)
if e != nil {
return nil, e
}
return &State{mode}, nil
}
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
func DisableEcho(fd uintptr, state *State) error {
state.mode &^= (ENABLE_ECHO_INPUT)
state.mode |= (ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)
return SetConsoleMode(fd, state.mode)
}
func SetRawTerminal(fd uintptr) (*State, error) {
oldState, err := MakeRaw(fd)
if err != nil {
return nil, err
}
// TODO (azlinux): implement handling interrupt and restore state of terminal
return oldState, err
}
// MakeRaw puts the terminal connected to the given file descriptor into raw
// mode and returns the previous state of the terminal so that it can be
// restored.
func MakeRaw(fd uintptr) (*State, error) {
var state *State
state, err := SaveState(fd)
if err != nil {
return nil, err
}
// see http://msdn.microsoft.com/en-us/library/windows/desktop/ms683462(v=vs.85).aspx for these flag settings
state.mode &^= (ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT)
err = SetConsoleMode(fd, state.mode)
if err != nil {
return nil, err
}
return state, nil
}

View file

@ -2,16 +2,20 @@
set -e
DEST=$1
BINARY_NAME="docker-$VERSION"
if [ "$(go env GOOS)" = 'windows' ]; then
BINARY_NAME+='.exe'
fi
go build \
-o "$DEST/docker-$VERSION" \
-o "$DEST/$BINARY_NAME" \
"${BUILDFLAGS[@]}" \
-ldflags "
$LDFLAGS
$LDFLAGS_STATIC_DOCKER
" \
./docker
echo "Created binary: $DEST/docker-$VERSION"
ln -sf "docker-$VERSION" "$DEST/docker"
echo "Created binary: $DEST/$BINARY_NAME"
ln -sf "$BINARY_NAME" "$DEST/docker"
hash_files "$DEST/docker-$VERSION"
hash_files "$DEST/$BINARY_NAME"

View file

@ -9,7 +9,7 @@ import (
)
func parse(t *testing.T, args string) (*Config, *HostConfig, error) {
config, hostConfig, _, err := parseRun(strings.Split(args+" ubuntu bash", " "), nil)
config, hostConfig, _, err := parseRun(strings.Split(args+" ubuntu bash", " "))
return config, hostConfig, err
}

View file

@ -10,7 +10,6 @@ import (
"github.com/docker/docker/opts"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/pkg/units"
"github.com/docker/docker/utils"
)
@ -24,7 +23,7 @@ var (
ErrConflictHostNetworkAndLinks = fmt.Errorf("Conflicting options: --net=host can't be used with links. This would result in undefined behavior.")
)
func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
var (
// FIXME: use utils.ListOpts for attach and volumes?
flAttach = opts.NewListOpts(opts.ValidateAttach)
@ -88,11 +87,6 @@ func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config,
return nil, nil, cmd, err
}
// Check if the kernel supports memory limit cgroup.
if sysInfo != nil && *flMemoryString != "" && !sysInfo.MemoryLimit {
*flMemoryString = ""
}
// Validate input params
if *flWorkingDir != "" && !path.IsAbs(*flWorkingDir) {
return nil, nil, cmd, ErrInvalidWorkingDirectory
@ -302,11 +296,6 @@ func Parse(cmd *flag.FlagSet, args []string, sysInfo *sysinfo.SysInfo) (*Config,
RestartPolicy: restartPolicy,
}
if sysInfo != nil && flMemory > 0 && !sysInfo.SwapLimit {
//fmt.Fprintf(stdout, "WARNING: Your kernel does not support swap limit capabilities. Limitation discarded.\n")
config.MemorySwap = -1
}
// When allocating stdin in attached mode, close stdin at client disconnect
if config.OpenStdin && config.AttachStdin {
config.StdinOnce = true

View file

@ -6,14 +6,13 @@ import (
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/sysinfo"
)
func parseRun(args []string, sysInfo *sysinfo.SysInfo) (*Config, *HostConfig, *flag.FlagSet, error) {
func parseRun(args []string) (*Config, *HostConfig, *flag.FlagSet, error) {
cmd := flag.NewFlagSet("run", flag.ContinueOnError)
cmd.SetOutput(ioutil.Discard)
cmd.Usage = nil
return Parse(cmd, args, sysInfo)
return Parse(cmd, args)
}
func TestParseLxcConfOpt(t *testing.T) {
@ -34,27 +33,27 @@ func TestParseLxcConfOpt(t *testing.T) {
}
func TestNetHostname(t *testing.T) {
if _, _, _, err := parseRun([]string{"-h=name", "img", "cmd"}, nil); err != nil {
if _, _, _, err := parseRun([]string{"-h=name", "img", "cmd"}); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
if _, _, _, err := parseRun([]string{"--net=host", "img", "cmd"}, nil); err != nil {
if _, _, _, err := parseRun([]string{"--net=host", "img", "cmd"}); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
if _, _, _, err := parseRun([]string{"-h=name", "--net=bridge", "img", "cmd"}, nil); err != nil {
if _, _, _, err := parseRun([]string{"-h=name", "--net=bridge", "img", "cmd"}); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
if _, _, _, err := parseRun([]string{"-h=name", "--net=none", "img", "cmd"}, nil); err != nil {
if _, _, _, err := parseRun([]string{"-h=name", "--net=none", "img", "cmd"}); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
if _, _, _, err := parseRun([]string{"-h=name", "--net=host", "img", "cmd"}, nil); err != ErrConflictNetworkHostname {
if _, _, _, err := parseRun([]string{"-h=name", "--net=host", "img", "cmd"}); err != ErrConflictNetworkHostname {
t.Fatalf("Expected error ErrConflictNetworkHostname, got: %s", err)
}
if _, _, _, err := parseRun([]string{"-h=name", "--net=container:other", "img", "cmd"}, nil); err != ErrConflictNetworkHostname {
if _, _, _, err := parseRun([]string{"-h=name", "--net=container:other", "img", "cmd"}); err != ErrConflictNetworkHostname {
t.Fatalf("Expected error ErrConflictNetworkHostname, got: %s", err)
}
}

View file

@ -1,12 +1,16 @@
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
package utils
import (
"os"
"path/filepath"
)
// TempDir returns the default directory to use for temporary files.
func TempDir(rootdir string) (string error) {
return os.TempDir(), nil
func TempDir(rootDir string) (string, error) {
var tmpDir string
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
tmpDir = filepath.Join(rootDir, "tmp")
}
err := os.MkdirAll(tmpDir, 0700)
return tmpDir, err
}

View file

@ -1,18 +0,0 @@
// +build darwin dragonfly freebsd linux netbsd openbsd
package utils
import (
"os"
"path/filepath"
)
// TempDir returns the default directory to use for temporary files.
func TempDir(rootDir string) (string, error) {
var tmpDir string
if tmpDir = os.Getenv("DOCKER_TMPDIR"); tmpDir == "" {
tmpDir = filepath.Join(rootDir, "tmp")
}
err := os.MkdirAll(tmpDir, 0700)
return tmpDir, err
}

View file

@ -18,7 +18,6 @@ import (
"strconv"
"strings"
"sync"
"syscall"
log "github.com/Sirupsen/logrus"
"github.com/docker/docker/dockerversion"
@ -453,36 +452,6 @@ func ReadSymlinkedDirectory(path string) (string, error) {
return realPath, nil
}
// TreeSize walks a directory tree and returns its total size in bytes.
func TreeSize(dir string) (size int64, err error) {
data := make(map[uint64]struct{})
err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, e error) error {
// Ignore directory sizes
if fileInfo == nil {
return nil
}
s := fileInfo.Size()
if fileInfo.IsDir() || s == 0 {
return nil
}
// Check inode to handle hard links correctly
inode := fileInfo.Sys().(*syscall.Stat_t).Ino
// inode is not a uint64 on all platforms. Cast it to avoid issues.
if _, exists := data[uint64(inode)]; exists {
return nil
}
// inode is not a uint64 on all platforms. Cast it to avoid issues.
data[uint64(inode)] = struct{}{}
size += s
return nil
})
return
}
// ValidateContextDirectory checks if all the contents of the directory
// can be read and returns an error if some files can't be read
// symlinks which point to non-existing files don't trigger an error

39
utils/utils_daemon.go Normal file
View file

@ -0,0 +1,39 @@
// +build daemon
package utils
import (
"os"
"path/filepath"
"syscall"
)
// TreeSize walks a directory tree and returns its total size in bytes.
func TreeSize(dir string) (size int64, err error) {
data := make(map[uint64]struct{})
err = filepath.Walk(dir, func(d string, fileInfo os.FileInfo, e error) error {
// Ignore directory sizes
if fileInfo == nil {
return nil
}
s := fileInfo.Size()
if fileInfo.IsDir() || s == 0 {
return nil
}
// Check inode to handle hard links correctly
inode := fileInfo.Sys().(*syscall.Stat_t).Ino
// inode is not a uint64 on all platforms. Cast it to avoid issues.
if _, exists := data[uint64(inode)]; exists {
return nil
}
// inode is not a uint64 on all platforms. Cast it to avoid issues.
data[uint64(inode)] = struct{}{}
size += s
return nil
})
return
}