mirror of
https://github.com/clearlinux/docker.git
synced 2026-08-21 13:18:00 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a6e81cff5f | |||
| 023d4ed189 | |||
| d7c5f31c5b | |||
| e51462ac68 | |||
| e45d0eb532 | |||
| 6bf1c41b77 |
@@ -1,32 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## 1.8.2 (2015-09-03)
|
||||
|
||||
### Distribution:
|
||||
|
||||
- Fixes rare edge case of handling GNU LongLink and LongName entries.
|
||||
- Avoid buffering to tempfile when pushing to registry V2.
|
||||
- Fix ^C on docker pull.
|
||||
- Fix docker pull issues on client disconnection.
|
||||
- Fix issue that caused the daemon to panic when loggers weren't configured properly.
|
||||
- Fix goroutine leak pulling images from registry V2.
|
||||
### Runtime:
|
||||
|
||||
- Fix a bug mounting cgroups for docker daemons running inside docker containers.
|
||||
- Initialize log configuration properly.
|
||||
|
||||
### Client:
|
||||
|
||||
- Handle `-q` flag in `docker ps` properly when there is a default format.
|
||||
|
||||
### Networking:
|
||||
|
||||
- Fix several corner cases with netlink.
|
||||
|
||||
### Contrib:
|
||||
|
||||
- Fix several issues with bash completion.
|
||||
|
||||
## 1.8.1 (2015-08-12)
|
||||
|
||||
### Distribution
|
||||
|
||||
+1
-1
@@ -127,7 +127,7 @@ RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint
|
||||
RUN gem install --no-rdoc --no-ri fpm --version 1.3.2
|
||||
|
||||
# Install registry
|
||||
ENV REGISTRY_COMMIT ec87e9b6971d831f0eff752ddb54fb64693e51cd
|
||||
ENV REGISTRY_COMMIT 2317f721a3d8428215a2b65da4ae85212ed473b4
|
||||
RUN set -x \
|
||||
&& export GOPATH="$(mktemp -d)" \
|
||||
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
|
||||
|
||||
+1
-1
@@ -95,7 +95,7 @@ func (cli *DockerCli) CmdPs(args ...string) error {
|
||||
|
||||
f := *format
|
||||
if len(f) == 0 {
|
||||
if len(cli.PsFormat()) > 0 && !*quiet {
|
||||
if len(cli.PsFormat()) > 0 {
|
||||
f = cli.PsFormat()
|
||||
} else {
|
||||
f = "table"
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ubuntu:precise
|
||||
FROM ubuntu-debootstrap:precise
|
||||
|
||||
RUN apt-get update && apt-get install -y bash-completion build-essential curl ca-certificates debhelper git libapparmor-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ubuntu:wily
|
||||
FROM ubuntu-debootstrap:trusty
|
||||
|
||||
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ubuntu:vivid
|
||||
FROM ubuntu-debootstrap:vivid
|
||||
|
||||
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/deb/generate.sh"!
|
||||
#
|
||||
|
||||
FROM ubuntu:trusty
|
||||
FROM ubuntu-debootstrap:wily
|
||||
|
||||
RUN apt-get update && apt-get install -y bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-systemd git libapparmor-dev libdevmapper-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
|
||||
|
||||
@@ -139,7 +139,7 @@ __docker_value_of_option() {
|
||||
local counter=$((command_pos + 1))
|
||||
while [ $counter -lt $cword ]; do
|
||||
case ${words[$counter]} in
|
||||
@($option_glob) )
|
||||
$option_glob )
|
||||
echo ${words[$counter + 1]}
|
||||
break
|
||||
;;
|
||||
@@ -229,12 +229,11 @@ __docker_log_driver_options() {
|
||||
# see docs/reference/logging/index.md
|
||||
local fluentd_options="fluentd-address fluentd-tag"
|
||||
local gelf_options="gelf-address gelf-tag"
|
||||
local json_file_options="max-file max-size"
|
||||
local syslog_options="syslog-address syslog-facility syslog-tag"
|
||||
|
||||
case $(__docker_value_of_option --log-driver) in
|
||||
'')
|
||||
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $json_file_options $syslog_options" -S = -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "$fluentd_options $gelf_options $syslog_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
fluentd)
|
||||
COMPREPLY=( $( compgen -W "$fluentd_options" -S = -- "$cur" ) )
|
||||
@@ -242,9 +241,6 @@ __docker_log_driver_options() {
|
||||
gelf)
|
||||
COMPREPLY=( $( compgen -W "$gelf_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
json-file)
|
||||
COMPREPLY=( $( compgen -W "$json_file_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
syslog)
|
||||
COMPREPLY=( $( compgen -W "$syslog_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
@@ -324,7 +320,7 @@ __docker_signals() {
|
||||
_docker_docker() {
|
||||
local boolean_options="
|
||||
$global_boolean_options
|
||||
--help
|
||||
--help -h
|
||||
--version -v
|
||||
"
|
||||
|
||||
@@ -342,6 +338,8 @@ _docker_docker() {
|
||||
;;
|
||||
esac
|
||||
|
||||
__docker_complete_log_driver_options && return
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "$boolean_options $global_options_with_args" -- "$cur" ) )
|
||||
@@ -462,7 +460,7 @@ _docker_create() {
|
||||
_docker_daemon() {
|
||||
local boolean_options="
|
||||
$global_boolean_options
|
||||
--help
|
||||
--help -h
|
||||
--icc=false
|
||||
--ip-forward=false
|
||||
--ip-masq=false
|
||||
@@ -514,39 +512,7 @@ _docker_daemon() {
|
||||
return
|
||||
;;
|
||||
--storage-driver|-s)
|
||||
COMPREPLY=( $( compgen -W "aufs btrfs devicemapper overlay vfs zfs" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
|
||||
return
|
||||
;;
|
||||
--storage-opt)
|
||||
local devicemapper_options="
|
||||
dm.basesize
|
||||
dm.blkdiscard
|
||||
dm.blocksize
|
||||
dm.fs
|
||||
dm.loopdatasize
|
||||
dm.loopmetadatasize
|
||||
dm.mkfsarg
|
||||
dm.mountopt
|
||||
dm.override_udev_sync_check
|
||||
dm.thinpooldev
|
||||
"
|
||||
local zfs_options="zfs.fsname"
|
||||
|
||||
case $(__docker_value_of_option '--storage-driver|-s') in
|
||||
'')
|
||||
COMPREPLY=( $( compgen -W "$devicemapper_options $zfs_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
devicemapper)
|
||||
COMPREPLY=( $( compgen -W "$devicemapper_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
zfs)
|
||||
COMPREPLY=( $( compgen -W "$zfs_options" -S = -- "$cur" ) )
|
||||
;;
|
||||
*)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
compopt -o nospace
|
||||
COMPREPLY=( $( compgen -W "aufs devicemapper btrfs overlay" -- "$(echo $cur | tr '[:upper:]' '[:lower:]')" ) )
|
||||
return
|
||||
;;
|
||||
--log-level|-l)
|
||||
@@ -562,27 +528,6 @@ _docker_daemon() {
|
||||
;;
|
||||
esac
|
||||
|
||||
__docker_complete_log_driver_options && return
|
||||
|
||||
case "${words[$cword-2]}$prev=" in
|
||||
*dm.blkdiscard=*)
|
||||
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
|
||||
return
|
||||
;;
|
||||
*dm.fs=*)
|
||||
COMPREPLY=( $( compgen -W "ext4 xfs" -- "${cur#=}" ) )
|
||||
return
|
||||
;;
|
||||
*dm.override_udev_sync_check=*)
|
||||
COMPREPLY=( $( compgen -W "false true" -- "${cur#=}" ) )
|
||||
return
|
||||
;;
|
||||
*dm.thinpooldev=*)
|
||||
_filedir
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
|
||||
@@ -924,7 +869,7 @@ _docker_ps() {
|
||||
compopt -o nospace
|
||||
return
|
||||
;;
|
||||
--format|-n)
|
||||
-n)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
@@ -948,7 +893,7 @@ _docker_ps() {
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "--all -a --before --filter -f --format --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "--all -a --before --filter -f --help --latest -l -n --no-trunc --quiet -q --size -s --since" -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -1053,16 +998,15 @@ _docker_rmi() {
|
||||
_docker_run() {
|
||||
local options_with_args="
|
||||
--add-host
|
||||
--attach -a
|
||||
--blkio-weight
|
||||
--attach -a
|
||||
--cap-add
|
||||
--cap-drop
|
||||
--cgroup-parent
|
||||
--cidfile
|
||||
--cpuset
|
||||
--cpu-period
|
||||
--cpu-quota
|
||||
--cpuset-cpus
|
||||
--cpuset-mems
|
||||
--cpu-shares -c
|
||||
--device
|
||||
--dns
|
||||
@@ -1074,8 +1018,8 @@ _docker_run() {
|
||||
--group-add
|
||||
--hostname -h
|
||||
--ipc
|
||||
--label-file
|
||||
--label -l
|
||||
--label-file
|
||||
--link
|
||||
--log-driver
|
||||
--log-opt
|
||||
@@ -1083,15 +1027,14 @@ _docker_run() {
|
||||
--mac-address
|
||||
--memory -m
|
||||
--memory-swap
|
||||
--memory-swappiness
|
||||
--name
|
||||
--net
|
||||
--pid
|
||||
--publish -p
|
||||
--restart
|
||||
--security-opt
|
||||
--ulimit
|
||||
--user -u
|
||||
--ulimit
|
||||
--uts
|
||||
--volumes-from
|
||||
--volume -v
|
||||
@@ -1099,10 +1042,8 @@ _docker_run() {
|
||||
"
|
||||
|
||||
local all_options="$options_with_args
|
||||
--disable-content-trust=false
|
||||
--help
|
||||
--interactive -i
|
||||
--oom-kill-disable
|
||||
--privileged
|
||||
--publish-all -P
|
||||
--read-only
|
||||
@@ -1112,7 +1053,7 @@ _docker_run() {
|
||||
[ "$command" = "run" ] && all_options="$all_options
|
||||
--detach -d
|
||||
--rm
|
||||
--sig-proxy=false
|
||||
--sig-proxy
|
||||
"
|
||||
|
||||
local options_with_args_glob=$(__docker_to_extglob "$options_with_args")
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
var (
|
||||
defaultPidFile = "/var/run/docker.pid"
|
||||
defaultGraph = "/var/lib/docker"
|
||||
defaultExec = "native"
|
||||
defaultExec = "clr"
|
||||
)
|
||||
|
||||
// Config defines the configuration of a docker daemon.
|
||||
|
||||
+1
-1
@@ -979,7 +979,7 @@ func getDefaultRouteMtu() (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
for _, r := range routes {
|
||||
if r.Default && r.Iface != nil {
|
||||
if r.Default {
|
||||
return r.Iface.MTU, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,721 @@
|
||||
// +build linux
|
||||
|
||||
package clr
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"net"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
sysinfo "github.com/docker/docker/pkg/system"
|
||||
"github.com/docker/docker/pkg/term"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
"github.com/kr/pty"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
|
||||
const (
|
||||
// Clear Linux for Intel(R) Architecture
|
||||
driverName = "clr"
|
||||
|
||||
envVarPrefix = "CLR_"
|
||||
|
||||
// Command used for lkvm control
|
||||
lkvmName = "lkvm"
|
||||
|
||||
// local "latest" information
|
||||
clrFile = "latest"
|
||||
|
||||
// upstream base URL
|
||||
clrURL = "https://download.clearlinux.org"
|
||||
|
||||
// upstream latest release file
|
||||
latestFile = "https://download.clearlinux.org/latest"
|
||||
|
||||
// clr kernel (not bzimage)
|
||||
clrKernel = "/usr/lib/kernel/vmlinux.container"
|
||||
)
|
||||
|
||||
type driver struct {
|
||||
root string // root path for the driver to use
|
||||
libPath string
|
||||
initPath string
|
||||
version string
|
||||
apparmor bool
|
||||
sharedRoot bool
|
||||
activeContainers map[string]*activeContainer
|
||||
machineMemory int64
|
||||
containerPid int
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
type activeContainer struct {
|
||||
container *configs.Config
|
||||
cmd *exec.Cmd
|
||||
}
|
||||
|
||||
func getTapIf(c *execdriver.Command) string {
|
||||
return fmt.Sprintf("tb-%s", c.ID[:12])
|
||||
}
|
||||
|
||||
func getClrVersion(libPath string) string {
|
||||
txt, err := ioutil.ReadFile(path.Join(libPath, clrFile))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return strings.Split(string(txt), "\n")[0]
|
||||
}
|
||||
|
||||
func fetchLatest(libPath string) error {
|
||||
out, err := os.Create(path.Join(libPath, clrFile))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
resp, err := http.Get(latestFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func fetchImage(version, libPath string) error {
|
||||
// TODO: Add checksum validation
|
||||
outfile := fmt.Sprintf("clear-%s-containers.img.xz", version)
|
||||
url := fmt.Sprintf("%s/releases/%s/clear/%s", clrURL, version, outfile)
|
||||
outpath := path.Join(libPath, outfile)
|
||||
var output []byte
|
||||
|
||||
logrus.Debugf("Fetching clr version: %s, %s", version, outpath)
|
||||
out, err := os.Create(outpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
// Consider progress feedback ?
|
||||
_, err = io.Copy(out, resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// decompress the file
|
||||
cmd := exec.Command("unxz", outpath)
|
||||
cmd.Dir = libPath
|
||||
|
||||
if output, err = cmd.CombinedOutput(); err != nil {
|
||||
logrus.Debugf("Unable to extract image %s: %s", version, output)
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewDriver creates a new clear linux execution driver.
|
||||
func NewDriver(root, libPath, initPath string, apparmor bool) (*driver, error) {
|
||||
if err := os.MkdirAll(root, 0700); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
meminfo, err := sysinfo.ReadMemInfo()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
version, err := prepareClr(libPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &driver{
|
||||
apparmor: apparmor,
|
||||
root: root,
|
||||
libPath: libPath,
|
||||
initPath: initPath,
|
||||
version: version,
|
||||
sharedRoot: false,
|
||||
activeContainers: make(map[string]*activeContainer),
|
||||
// FIXME:
|
||||
machineMemory: meminfo.MemTotal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func prepareClr(libPath string) (string, error) {
|
||||
var version = getClrVersion(libPath)
|
||||
var nversion string
|
||||
logrus.Debugf("%s preparing environment", driverName)
|
||||
|
||||
err := fetchLatest(libPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nversion = getClrVersion(libPath)
|
||||
if nversion != version && version != "" {
|
||||
logrus.Debugf("Updating to clr version: %s", nversion)
|
||||
err = fetchImage(nversion, libPath)
|
||||
} else if version == "" {
|
||||
logrus.Debugf("Installing clr version: %s", nversion)
|
||||
err = fetchImage(nversion, libPath)
|
||||
} else {
|
||||
logrus.Debugf("Using clr version: %s", nversion)
|
||||
}
|
||||
|
||||
return nversion, nil
|
||||
}
|
||||
|
||||
func (d *driver) Name() string {
|
||||
return fmt.Sprintf("%s-%s", driverName, d.version)
|
||||
}
|
||||
|
||||
func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (execdriver.ExitStatus, error) {
|
||||
var (
|
||||
term execdriver.Terminal
|
||||
err error
|
||||
)
|
||||
|
||||
container, err := d.createContainer(c)
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
memoryMiB := c.HostConfig.Memory
|
||||
if memoryMiB == 0 {
|
||||
memoryMiB = 1024
|
||||
} else {
|
||||
// docker passes the value as bytes
|
||||
memoryMiB = memoryMiB / int64(math.Pow(2, 20))
|
||||
}
|
||||
|
||||
workingDirVar := fmt.Sprintf("%s%s=%q", envVarPrefix, "WORKINGDIR", c.WorkingDir)
|
||||
c.ProcessConfig.Cmd.Env = append(c.ProcessConfig.Cmd.Env, workingDirVar)
|
||||
|
||||
userVar := fmt.Sprintf("%s%s=%q", envVarPrefix, "USER", c.ProcessConfig.User)
|
||||
c.ProcessConfig.Cmd.Env = append(c.ProcessConfig.Cmd.Env, userVar)
|
||||
|
||||
if err := d.setupNetwork(c); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
if c.ProcessConfig.Tty {
|
||||
term, err = NewTtyConsole(&c.ProcessConfig, pipes)
|
||||
} else {
|
||||
term, err = execdriver.NewStdConsole(&c.ProcessConfig, pipes)
|
||||
}
|
||||
if err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
c.ProcessConfig.Terminal = term
|
||||
|
||||
d.Lock()
|
||||
d.activeContainers[c.ID] = &activeContainer{
|
||||
container: container,
|
||||
cmd: &c.ProcessConfig.Cmd,
|
||||
}
|
||||
d.Unlock()
|
||||
|
||||
if err := d.generateEnvConfig(c); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
if err := d.generateDockerInit(c); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
for _, m := range c.Mounts {
|
||||
dest := path.Join(c.Rootfs, m.Destination)
|
||||
|
||||
if m.Destination == "/etc/hostname" {
|
||||
continue
|
||||
}
|
||||
|
||||
if !pathExists(m.Source) {
|
||||
continue
|
||||
}
|
||||
|
||||
opts := "bind"
|
||||
|
||||
if m.Private {
|
||||
opts = opts + ",rprivate"
|
||||
}
|
||||
if m.Slave {
|
||||
opts = opts + ",rslave"
|
||||
}
|
||||
|
||||
// This may look racy, but it isn't since the VM isn't
|
||||
// running yet.
|
||||
//
|
||||
// The check is necessary to handle bind mounting of
|
||||
// regular files correctly since without it we may be
|
||||
// attempting to create a directory where there already
|
||||
// exists a normal file.
|
||||
if !pathExists(dest) {
|
||||
if err := os.MkdirAll(dest, 0750); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
}
|
||||
|
||||
if err := mount.Mount(m.Source, dest, "", opts); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
if !m.Writable {
|
||||
if err := mount.Mount("", dest, "", "bind,remount,ro"); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
}
|
||||
defer mount.Unmount(dest)
|
||||
}
|
||||
|
||||
var args []string
|
||||
// various things for lkvm
|
||||
ifname := getTapIf(c)
|
||||
// FIXME: Should be real hostname from like process/container struct
|
||||
hostname := c.ID[0:12]
|
||||
img := fmt.Sprintf("%s/clear-%s-containers.img", d.libPath, d.version)
|
||||
memory := fmt.Sprintf("%d", memoryMiB)
|
||||
// FIXME: Locked cores to 6 ?
|
||||
cores := fmt.Sprintf("%d", 6)
|
||||
ipaddr := c.NetworkSettings.IPAddress
|
||||
gateway := c.NetworkSettings.Gateway
|
||||
macaddr := c.NetworkSettings.MacAddress
|
||||
|
||||
args = append(args, c.ProcessConfig.Entrypoint)
|
||||
args = append(args, c.ProcessConfig.Arguments...)
|
||||
|
||||
rootParams := fmt.Sprintf("root=/dev/plkvm0p1 rootfstype=ext4 rootflags=dax,data=ordered "+
|
||||
"init=/usr/lib/systemd/systemd systemd.unit=container.target rw tsc=reliable "+
|
||||
"systemd.show_status=false "+
|
||||
"no_timer_check rcupdate.rcu_expedited=1 console=hvc0 quiet ip=%s::%s::%s::off",
|
||||
ipaddr, gateway, hostname)
|
||||
|
||||
params := []string{
|
||||
lkvmName, "run", "-c", cores, "-m", memory,
|
||||
"--name", c.ID, "--console", "virtio",
|
||||
"--kernel", clrKernel,
|
||||
"--params", rootParams,
|
||||
"--shmem", fmt.Sprintf("0x200000000:0:file=%s:private", img),
|
||||
"--network", fmt.Sprintf("mode=tap,script=none,tapif=%s,guest_mac=%s", ifname, macaddr),
|
||||
"--9p", fmt.Sprintf("%s,rootfs", c.Rootfs),
|
||||
}
|
||||
|
||||
logrus.Debugf("%s params %s", driverName, params)
|
||||
var (
|
||||
name = params[0]
|
||||
arg = params[1:]
|
||||
)
|
||||
aname, err := exec.LookPath(name)
|
||||
if err != nil {
|
||||
aname = name
|
||||
}
|
||||
c.ProcessConfig.Path = aname
|
||||
c.ProcessConfig.Args = append([]string{name}, arg...)
|
||||
c.ProcessConfig.Env = []string{fmt.Sprintf("HOME=%s", d.root)}
|
||||
|
||||
// Start the container. Since it runs synchronously, we don't Wait()
|
||||
// for it since we need to check the status to determine if it did
|
||||
// actually start successfully.
|
||||
if err := c.ProcessConfig.Start(); err != nil {
|
||||
return execdriver.ExitStatus{ExitCode: -1}, err
|
||||
}
|
||||
|
||||
var (
|
||||
waitErr error
|
||||
waitLock = make(chan struct{})
|
||||
)
|
||||
go func() {
|
||||
if err := c.ProcessConfig.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)
|
||||
}()
|
||||
|
||||
// FIXME: need to create state.json for Stats() to work.
|
||||
c.ContainerPid = c.ProcessConfig.Process.Pid
|
||||
d.containerPid = c.ProcessConfig.Process.Pid
|
||||
|
||||
if startCallback != nil {
|
||||
logrus.Debugf("Invoking startCallback")
|
||||
startCallback(&c.ProcessConfig, c.ProcessConfig.Process.Pid)
|
||||
}
|
||||
|
||||
// FIXME:
|
||||
oomKill := false
|
||||
|
||||
// Wait for the VM to shutdown
|
||||
<-waitLock
|
||||
exitCode := getExitCode(c)
|
||||
|
||||
cExitStatus, cerr := d.cleanupVM(c)
|
||||
|
||||
if cerr != nil {
|
||||
waitErr = cerr
|
||||
exitCode = cExitStatus
|
||||
}
|
||||
|
||||
// check oom error
|
||||
if oomKill {
|
||||
exitCode = 137
|
||||
}
|
||||
|
||||
return execdriver.ExitStatus{ExitCode: exitCode, OOMKilled: false}, waitErr
|
||||
}
|
||||
|
||||
func pathExists(path string) bool {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func pathExecutable(path string) bool {
|
||||
s, err := os.Stat(path)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
mode := s.Mode()
|
||||
if mode&0111 != 0 {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *driver) cleanupVM(c *execdriver.Command) (exitStatus int, err error) {
|
||||
cmd := exec.Command("ip", "tuntap", "del", "dev", getTapIf(c), "mode", "tap")
|
||||
var output []byte
|
||||
|
||||
if output, err = cmd.CombinedOutput(); err != nil {
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
waitStatus := exitError.Sys().(syscall.WaitStatus)
|
||||
exitStatus = waitStatus.ExitStatus()
|
||||
}
|
||||
logrus.Debugf("teardown failed for vm %s: %s (%s)", c.ID, string(output), err.Error())
|
||||
}
|
||||
|
||||
// doesn't matter if this fails
|
||||
// lkvm could have removed it, and stale sockets are not fatal
|
||||
_ = os.Remove(fmt.Sprintf("%s/.lkvm/%s.sock", d.root, c.ID))
|
||||
|
||||
return exitStatus, err
|
||||
}
|
||||
|
||||
// createContainer populates and configures the container type with the
|
||||
// data provided by the execdriver.Command
|
||||
func (d *driver) createContainer(c *execdriver.Command) (*configs.Config, error) {
|
||||
return execdriver.InitContainer(c), nil
|
||||
}
|
||||
|
||||
/// 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.ProcessConfig.ProcessState == nil {
|
||||
return -1
|
||||
}
|
||||
return c.ProcessConfig.ProcessState.Sys().(syscall.WaitStatus).ExitStatus()
|
||||
}
|
||||
|
||||
func (d *driver) lkvmCommand(c *execdriver.Command, arg string) ([]byte, error) {
|
||||
args := append([]string{lkvmName}, arg)
|
||||
if c != nil {
|
||||
args = append(args, "--name", c.ID)
|
||||
}
|
||||
cmd := exec.Command(lkvmName, args...)
|
||||
cmd.Env = []string{fmt.Sprintf("HOME=%s", d.root)}
|
||||
return cmd.Output()
|
||||
}
|
||||
|
||||
// Kill sends a signal to workload
|
||||
func (d *driver) Kill(c *execdriver.Command, sig int) error {
|
||||
// Not supported
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) Pause(c *execdriver.Command) error {
|
||||
_, err := d.lkvmCommand(c, "pause")
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) Unpause(c *execdriver.Command) error {
|
||||
_, err := d.lkvmCommand(c, "resume")
|
||||
return err
|
||||
}
|
||||
|
||||
// Terminate forcibly stops a container
|
||||
func (d *driver) Terminate(c *execdriver.Command) error {
|
||||
_, err := d.lkvmCommand(c, "stop")
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) containerDir(containerID string) string {
|
||||
return path.Join(d.libPath, "containers", containerID)
|
||||
}
|
||||
|
||||
// isDigit returns true if s can be represented as an integer
|
||||
func isDigit(s string) bool {
|
||||
if _, err := strconv.Atoi(s); err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (d *driver) getInfo(id string) ([]byte, error) {
|
||||
output, err := d.lkvmCommand(nil, "list")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i, line := range strings.Split(string(output), "\n") {
|
||||
if i < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
fields := strings.Fields(strings.TrimSpace(line))
|
||||
|
||||
if len(fields) != 3 {
|
||||
continue
|
||||
}
|
||||
|
||||
if !isDigit(fields[0]) {
|
||||
continue
|
||||
}
|
||||
|
||||
if fields[1] != id {
|
||||
continue
|
||||
}
|
||||
|
||||
return []byte(line), nil
|
||||
}
|
||||
|
||||
return []byte(fmt.Sprintf("-1 %s stopped", id)), nil
|
||||
}
|
||||
|
||||
type info struct {
|
||||
ID string
|
||||
driver *driver
|
||||
}
|
||||
|
||||
func (i *info) IsRunning() bool {
|
||||
output, err := i.driver.getInfo(i.ID)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error getting info for %s container %s: %s (%s)",
|
||||
driverName, i.ID, err, output)
|
||||
return false
|
||||
}
|
||||
|
||||
clrInfo, err := parseClrInfo(i.ID, string(output))
|
||||
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return clrInfo.Running
|
||||
}
|
||||
|
||||
func (d *driver) Info(id string) execdriver.Info {
|
||||
return &info{
|
||||
ID: id,
|
||||
driver: d,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *driver) GetPidsForContainer(id string) ([]int, error) {
|
||||
// The VM doesn't expose the worload pid(s), so the only meaningful
|
||||
// pid is that of the VM
|
||||
return []int{d.containerPid}, nil
|
||||
}
|
||||
|
||||
// TtyConsole is a type to represent a pseud-oterminal (see pty(7))
|
||||
type TtyConsole struct {
|
||||
MasterPty *os.File
|
||||
SlavePty *os.File
|
||||
}
|
||||
|
||||
// NewTtyConsole returns a new TtyConsole object.
|
||||
func NewTtyConsole(processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes) (*TtyConsole, error) {
|
||||
// lxc is special in that we cannot create the master outside of the container without
|
||||
// opening the slave because we have nothing to provide to the cmd. We have to open both then do
|
||||
// the crazy setup on command right now instead of passing the console path to lxc and telling it
|
||||
// to open up that console. we save a couple of openfiles in the native driver because we can do
|
||||
// this.
|
||||
ptyMaster, ptySlave, err := pty.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tty := &TtyConsole{
|
||||
MasterPty: ptyMaster,
|
||||
SlavePty: ptySlave,
|
||||
}
|
||||
|
||||
if err := tty.AttachPipes(&processConfig.Cmd, pipes); err != nil {
|
||||
tty.Close()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
processConfig.Console = tty.SlavePty.Name()
|
||||
|
||||
return tty, nil
|
||||
}
|
||||
|
||||
// Master returns the master end of the pty
|
||||
func (t *TtyConsole) Master() *os.File {
|
||||
return t.MasterPty
|
||||
}
|
||||
|
||||
// Resize modifies the size of the pty terminal being used.
|
||||
func (t *TtyConsole) Resize(h, w int) error {
|
||||
return term.SetWinsize(t.MasterPty.Fd(), &term.Winsize{Height: uint16(h), Width: uint16(w)})
|
||||
}
|
||||
|
||||
// AttachPipes associates the specified pipes with the pty master.
|
||||
func (t *TtyConsole) AttachPipes(command *exec.Cmd, pipes *execdriver.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() {
|
||||
io.Copy(t.MasterPty, pipes.Stdin)
|
||||
|
||||
pipes.Stdin.Close()
|
||||
}()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close closes both ends of the pty.
|
||||
func (t *TtyConsole) Close() error {
|
||||
t.SlavePty.Close()
|
||||
return t.MasterPty.Close()
|
||||
}
|
||||
|
||||
func (d *driver) Exec(c *execdriver.Command, processConfig *execdriver.ProcessConfig, pipes *execdriver.Pipes, startCallback execdriver.StartCallback) (int, error) {
|
||||
return -1, fmt.Errorf("Unsupported: Exec is not supported by the %q driver", driverName)
|
||||
|
||||
}
|
||||
|
||||
// Clean up after an Exec
|
||||
func (d *driver) Clean(id string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *driver) generateEnvConfig(c *execdriver.Command) error {
|
||||
data := []byte(strings.Join(c.ProcessConfig.Env, "\n"))
|
||||
|
||||
p := path.Join(d.libPath, "containers", c.ID, "config.env")
|
||||
c.Mounts = append(c.Mounts, execdriver.Mount{
|
||||
Source: p,
|
||||
Destination: "/.dockerenv",
|
||||
Writable: false,
|
||||
Private: true,
|
||||
})
|
||||
|
||||
return ioutil.WriteFile(p, data, 0600)
|
||||
}
|
||||
|
||||
func (d *driver) generateDockerInit(c *execdriver.Command) error {
|
||||
p := fmt.Sprintf("%s/.containerexec", c.Rootfs)
|
||||
var args []string
|
||||
|
||||
if pathExecutable(p) {
|
||||
return nil
|
||||
}
|
||||
|
||||
args = append(args, c.ProcessConfig.Entrypoint)
|
||||
args = append(args, c.ProcessConfig.Arguments...)
|
||||
|
||||
data := []byte(fmt.Sprintf("#!/bin/sh\n%s\n", strings.Join(args, " ")))
|
||||
|
||||
return ioutil.WriteFile(p, data, 0755)
|
||||
}
|
||||
|
||||
func (d *driver) setupNetwork(c *execdriver.Command) error {
|
||||
ifname := getTapIf(c)
|
||||
|
||||
var bridgeName string
|
||||
var bridgeLinkName string
|
||||
var output []byte
|
||||
var err error
|
||||
|
||||
for _, info := range c.EndpointInfo {
|
||||
if mac, ok := info[netlabel.MacAddress].(net.HardwareAddr); ok {
|
||||
if mac.String() == c.NetworkSettings.MacAddress {
|
||||
bridgeName = info[netlabel.BridgeName].(string)
|
||||
bridgeLinkName = info[netlabel.BridgeLinkName].(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Strip existing veth
|
||||
cmd := exec.Command("ip", "link", "del", bridgeLinkName)
|
||||
if output, err = cmd.CombinedOutput(); err != nil {
|
||||
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
|
||||
return err
|
||||
}
|
||||
|
||||
cmd = exec.Command("ip", "tuntap", "add", "dev", ifname, "mode", "tap", "vnet_hdr")
|
||||
if output, err = cmd.CombinedOutput(); err != nil {
|
||||
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
|
||||
return err
|
||||
}
|
||||
cmd = exec.Command("ip", "link", "set", "dev", ifname, "master", bridgeName)
|
||||
if output, err = cmd.CombinedOutput(); err != nil {
|
||||
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
|
||||
return err
|
||||
}
|
||||
|
||||
cmd = exec.Command("ip", "link", "set", "dev", ifname, "up")
|
||||
if output, err = cmd.CombinedOutput(); err != nil {
|
||||
logrus.Debugf("%s setupNetwork error: %v, %s", driverName, cmd.Args, output)
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (d *driver) Stats(id string) (*execdriver.ResourceStats, error) {
|
||||
if _, ok := d.activeContainers[id]; !ok {
|
||||
return nil, fmt.Errorf("%s is not a key in active containers", id)
|
||||
}
|
||||
// FIXME:
|
||||
return execdriver.Stats(d.containerDir(id), d.activeContainers[id].container.Cgroups.Memory, d.machineMemory)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// +build linux
|
||||
|
||||
package clr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCannotParse = errors.New("cannot parse raw input")
|
||||
)
|
||||
|
||||
type clrInfo struct {
|
||||
Running bool
|
||||
Pid int
|
||||
}
|
||||
|
||||
func parseClrInfo(name, raw string) (*clrInfo, error) {
|
||||
if raw == "" {
|
||||
return nil, ErrCannotParse
|
||||
}
|
||||
var (
|
||||
err error
|
||||
info = &clrInfo{}
|
||||
)
|
||||
|
||||
fields := strings.Fields(strings.TrimSpace(raw))
|
||||
|
||||
// The format is expected to be:
|
||||
//
|
||||
// <pid> <name> <state>
|
||||
//
|
||||
if len(fields) != 3 {
|
||||
return nil, ErrCannotParse
|
||||
}
|
||||
|
||||
info.Pid, err = strconv.Atoi(fields[0])
|
||||
if err != nil {
|
||||
return nil, ErrCannotParse
|
||||
}
|
||||
|
||||
if fields[1] != name {
|
||||
return nil, ErrCannotParse
|
||||
}
|
||||
|
||||
info.Running = fields[2] == "running"
|
||||
|
||||
return info, nil
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
// +build linux
|
||||
|
||||
package clr
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// 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
|
||||
Console string
|
||||
Pipe int
|
||||
Root string
|
||||
CapAdd string
|
||||
CapDrop string
|
||||
}
|
||||
|
||||
func getArgs() *InitArgs {
|
||||
var (
|
||||
// Get cmdline arguments
|
||||
user = flag.String("u", "", "username or uid")
|
||||
gateway = flag.String("g", "", "gateway address")
|
||||
ip = flag.String("i", "", "ip address")
|
||||
workDir = flag.String("w", "", "workdir")
|
||||
privileged = flag.Bool("privileged", false, "privileged mode")
|
||||
mtu = flag.Int("mtu", 1500, "interface mtu")
|
||||
capAdd = flag.String("cap-add", "", "capabilities to add")
|
||||
capDrop = flag.String("cap-drop", "", "capabilities to drop")
|
||||
)
|
||||
|
||||
flag.Parse()
|
||||
|
||||
return &InitArgs{
|
||||
User: *user,
|
||||
Gateway: *gateway,
|
||||
Ip: *ip,
|
||||
WorkDir: *workDir,
|
||||
Privileged: *privileged,
|
||||
Args: flag.Args(),
|
||||
Mtu: *mtu,
|
||||
CapAdd: *capAdd,
|
||||
CapDrop: *capDrop,
|
||||
}
|
||||
}
|
||||
|
||||
// Clear environment pollution introduced by lxc-start
|
||||
func setupEnv(args *InitArgs) error {
|
||||
// Get env
|
||||
var env []string
|
||||
dockerenv, err := os.Open(".dockerenv")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to load environment variables: %v", err)
|
||||
}
|
||||
defer dockerenv.Close()
|
||||
if err := json.NewDecoder(dockerenv).Decode(&env); err != nil {
|
||||
return fmt.Errorf("Unable to decode environment variables: %v", err)
|
||||
}
|
||||
// Propagate the plugin-specific container env variable
|
||||
env = append(env, "container="+os.Getenv("container"))
|
||||
|
||||
args.Env = env
|
||||
|
||||
os.Clearenv()
|
||||
for _, kv := range args.Env {
|
||||
parts := strings.SplitN(kv, "=", 2)
|
||||
if len(parts) == 1 {
|
||||
parts = append(parts, "")
|
||||
}
|
||||
os.Setenv(parts[0], parts[1])
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Setup working directory
|
||||
func setupWorkingDirectory(args *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
|
||||
}
|
||||
+32
-27
@@ -7,7 +7,9 @@ import (
|
||||
"time"
|
||||
|
||||
// TODO Windows: Factor out ulimit
|
||||
"github.com/docker/docker/daemon/network"
|
||||
"github.com/docker/docker/pkg/ulimit"
|
||||
"github.com/docker/docker/runconfig"
|
||||
"github.com/opencontainers/runc/libcontainer"
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
)
|
||||
@@ -150,31 +152,34 @@ type ProcessConfig struct {
|
||||
//
|
||||
// Process wrapps an os/exec.Cmd to add more metadata
|
||||
type Command struct {
|
||||
ID string `json:"id"`
|
||||
Rootfs string `json:"rootfs"` // root fs of the container
|
||||
ReadonlyRootfs bool `json:"readonly_rootfs"`
|
||||
InitPath string `json:"initpath"` // dockerinit
|
||||
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
|
||||
Network *Network `json:"network"`
|
||||
Ipc *Ipc `json:"ipc"`
|
||||
Pid *Pid `json:"pid"`
|
||||
UTS *UTS `json:"uts"`
|
||||
Resources *Resources `json:"resources"`
|
||||
Mounts []Mount `json:"mounts"`
|
||||
AllowedDevices []*configs.Device `json:"allowed_devices"`
|
||||
AutoCreatedDevices []*configs.Device `json:"autocreated_devices"`
|
||||
CapAdd []string `json:"cap_add"`
|
||||
CapDrop []string `json:"cap_drop"`
|
||||
GroupAdd []string `json:"group_add"`
|
||||
ContainerPid int `json:"container_pid"` // the pid for the process inside a container
|
||||
ProcessConfig ProcessConfig `json:"process_config"` // Describes the init process of the container.
|
||||
ProcessLabel string `json:"process_label"`
|
||||
MountLabel string `json:"mount_label"`
|
||||
LxcConfig []string `json:"lxc_config"`
|
||||
AppArmorProfile string `json:"apparmor_profile"`
|
||||
CgroupParent string `json:"cgroup_parent"` // The parent cgroup for this command.
|
||||
FirstStart bool `json:"first_start"`
|
||||
LayerPaths []string `json:"layer_paths"` // Windows needs to know the layer paths and folder for a command
|
||||
LayerFolder string `json:"layer_folder"`
|
||||
ID string `json:"id"`
|
||||
Rootfs string `json:"rootfs"` // root fs of the container
|
||||
ReadonlyRootfs bool `json:"readonly_rootfs"`
|
||||
InitPath string `json:"initpath"` // dockerinit
|
||||
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
|
||||
Network *Network `json:"network"`
|
||||
Ipc *Ipc `json:"ipc"`
|
||||
Pid *Pid `json:"pid"`
|
||||
UTS *UTS `json:"uts"`
|
||||
Resources *Resources `json:"resources"`
|
||||
Mounts []Mount `json:"mounts"`
|
||||
AllowedDevices []*configs.Device `json:"allowed_devices"`
|
||||
AutoCreatedDevices []*configs.Device `json:"autocreated_devices"`
|
||||
CapAdd []string `json:"cap_add"`
|
||||
CapDrop []string `json:"cap_drop"`
|
||||
GroupAdd []string `json:"group_add"`
|
||||
ContainerPid int `json:"container_pid"` // the pid for the process inside a container
|
||||
ProcessConfig ProcessConfig `json:"process_config"` // Describes the init process of the container.
|
||||
ProcessLabel string `json:"process_label"`
|
||||
MountLabel string `json:"mount_label"`
|
||||
LxcConfig []string `json:"lxc_config"`
|
||||
AppArmorProfile string `json:"apparmor_profile"`
|
||||
CgroupParent string `json:"cgroup_parent"` // The parent cgroup for this command.
|
||||
FirstStart bool `json:"first_start"`
|
||||
LayerPaths []string `json:"layer_paths"` // Windows needs to know the layer paths and folder for a command
|
||||
LayerFolder string `json:"layer_folder"`
|
||||
NetworkSettings *network.Settings `json:"network_settings"`
|
||||
EndpointInfo []map[string]interface{} `json:"endpoint_info"`
|
||||
HostConfig *runconfig.HostConfig
|
||||
}
|
||||
|
||||
@@ -8,13 +8,17 @@ import (
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/execdriver"
|
||||
"github.com/docker/docker/daemon/execdriver/clr"
|
||||
"github.com/docker/docker/daemon/execdriver/lxc"
|
||||
"github.com/docker/docker/daemon/execdriver/native"
|
||||
"github.com/docker/docker/pkg/sysinfo"
|
||||
)
|
||||
|
||||
func NewDriver(name string, options []string, root, libPath, initPath string, sysInfo *sysinfo.SysInfo) (execdriver.Driver, error) {
|
||||
rootPath := path.Join(root, "execdriver", name)
|
||||
switch name {
|
||||
case "clr":
|
||||
return clr.NewDriver(rootPath, libPath, initPath, sysInfo.AppArmor)
|
||||
case "lxc":
|
||||
// we want to give the lxc driver the full docker root because it needs
|
||||
// to access and write config and template files in /var/lib/docker/containers/*
|
||||
@@ -22,7 +26,7 @@ func NewDriver(name string, options []string, root, libPath, initPath string, sy
|
||||
logrus.Warn("LXC built-in support is deprecated.")
|
||||
return lxc.NewDriver(root, libPath, initPath, sysInfo.AppArmor)
|
||||
case "native":
|
||||
return native.NewDriver(path.Join(root, "execdriver", "native"), initPath, options)
|
||||
return native.NewDriver(rootPath, initPath, options)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown exec driver %s", name)
|
||||
}
|
||||
|
||||
@@ -1482,12 +1482,16 @@ func (devices *DeviceSet) deactivatePool() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if d, err := devicemapper.GetDeps(devname); err == nil {
|
||||
// Access to more Debug output
|
||||
logrus.Debugf("[devmapper] devicemapper.GetDeps() %s: %#v", devname, d)
|
||||
|
||||
if devinfo.Exists == 0 {
|
||||
return nil
|
||||
}
|
||||
if devinfo.Exists != 0 {
|
||||
return devicemapper.RemoveDevice(devname)
|
||||
if err := devicemapper.RemoveDevice(devname); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if d, err := devicemapper.GetDeps(devname); err == nil {
|
||||
logrus.Warnf("[devmapper] device %s still has %d active dependents", devname, d.Count)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -138,6 +138,30 @@ func (m *containerMonitor) Start() error {
|
||||
|
||||
m.lastStartTime = time.Now()
|
||||
|
||||
// Make the network settings available to the execution
|
||||
// driver to allow for integration with libnetwork networking.
|
||||
m.container.command.NetworkSettings = m.container.NetworkSettings
|
||||
|
||||
// Allow the execution driver to query memory limits
|
||||
m.container.command.HostConfig = m.container.hostConfig
|
||||
|
||||
// Make the network endpoint details available to the execution
|
||||
// driver as well.
|
||||
n, _err := m.container.daemon.netController.NetworkByID(m.container.NetworkSettings.NetworkID)
|
||||
if _err == nil {
|
||||
var eps []map[string]interface{}
|
||||
|
||||
for _, ep := range n.Endpoints() {
|
||||
info, err := ep.DriverInfo()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
eps = append(eps, info)
|
||||
}
|
||||
|
||||
m.container.command.EndpointInfo = eps
|
||||
}
|
||||
|
||||
if exitStatus, err = m.container.daemon.Run(m.container, pipes, m.callback); err != nil {
|
||||
// if we receive an internal error from the initial start of a container then lets
|
||||
// return it instead of entering the restart loop
|
||||
|
||||
+4
-1
@@ -76,7 +76,6 @@ func NewDaemonCli() *DaemonCli {
|
||||
|
||||
// TODO(tiborvass): remove InstallFlags?
|
||||
daemonConfig := new(daemon.Config)
|
||||
daemonConfig.LogConfig.Config = make(map[string]string)
|
||||
daemonConfig.InstallFlags(daemonFlags, presentInHelp)
|
||||
daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp)
|
||||
registryOptions := new(registry.Options)
|
||||
@@ -209,6 +208,10 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
|
||||
}()
|
||||
}
|
||||
|
||||
if cli.LogConfig.Config == nil {
|
||||
cli.LogConfig.Config = make(map[string]string)
|
||||
}
|
||||
|
||||
serverConfig := &apiserver.ServerConfig{
|
||||
Logging: true,
|
||||
EnableCors: cli.EnableCors,
|
||||
|
||||
+1
-1
@@ -28,7 +28,7 @@ func main() {
|
||||
flag.Merge(flag.CommandLine, clientFlags.FlagSet, commonFlags.FlagSet)
|
||||
|
||||
flag.Usage = func() {
|
||||
fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n"+daemonUsage+" docker [ --help | -v | --version ]\n\n")
|
||||
fmt.Fprint(os.Stdout, "Usage: docker [OPTIONS] COMMAND [arg...]\n"+daemonUsage+" docker [ -h | --help | -v | --version ]\n\n")
|
||||
fmt.Fprint(os.Stdout, "A self-sufficient runtime for containers.\n\nOptions:\n")
|
||||
|
||||
flag.CommandLine.SetOutput(os.Stdout)
|
||||
|
||||
@@ -16,7 +16,7 @@ or execute `docker help`:
|
||||
$ docker
|
||||
Usage: docker [OPTIONS] COMMAND [arg...]
|
||||
docker daemon [ --help | ... ]
|
||||
docker [ --help | -v | --version ]
|
||||
docker [ -h | --help | -v | --version ]
|
||||
|
||||
-H, --host=[]: The socket(s) to bind to in daemon mode, specified using one or more tcp://host:port, unix:///path/to/socket, fd://* or fd://socketfd.
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ parent = "smn_cli"
|
||||
-G, --group="docker" Group for the unix socket
|
||||
-g, --graph="/var/lib/docker" Root of the Docker runtime
|
||||
-H, --host=[] Daemon socket(s) to connect to
|
||||
--help=false Print usage
|
||||
-h, --help=false Print usage
|
||||
--icc=true Enable inter-container communication
|
||||
--insecure-registry=[] Enable insecure registry communication
|
||||
--ip=0.0.0.0 Default IP when binding container ports
|
||||
|
||||
@@ -74,21 +74,16 @@ The output will provide details on the container configurations including the
|
||||
volumes. The output should look something similar to the following:
|
||||
|
||||
...
|
||||
Mounts": [
|
||||
{
|
||||
"Name": "fac362...80535",
|
||||
"Source": "/var/lib/docker/volumes/fac362...80535/_data",
|
||||
"Destination": "/webapp",
|
||||
"Driver": "local",
|
||||
"Mode": "",
|
||||
"RW": true
|
||||
}
|
||||
]
|
||||
"Volumes": {
|
||||
"/webapp": "/var/lib/docker/volumes/fac362...80535"
|
||||
},
|
||||
"VolumesRW": {
|
||||
"/webapp": true
|
||||
}
|
||||
...
|
||||
|
||||
You will notice in the above 'Source' is specifying the location on the host and
|
||||
'Destination' is specifying the volume location inside the container. `RW` shows
|
||||
if the volume is read/write.
|
||||
You will notice in the above 'Volumes' is specifying the location on the host and
|
||||
'VolumesRW' is specifying that the volume is read/write.
|
||||
|
||||
### Mount a host directory as a data volume
|
||||
|
||||
|
||||
+4
-10
@@ -77,7 +77,7 @@ func (p *v2Puller) pullV2Repository(tag string) (err error) {
|
||||
if err != nil {
|
||||
if c != nil {
|
||||
// Another pull of the same repository is already taking place; just wait for it to finish
|
||||
p.config.OutStream.Write(p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName))
|
||||
p.sf.FormatStatus("", "Repository %s already being pulled by another client. Waiting.", p.repoInfo.CanonicalName)
|
||||
<-c
|
||||
return nil
|
||||
}
|
||||
@@ -140,9 +140,9 @@ func (p *v2Puller) download(di *downloadInfo) {
|
||||
return
|
||||
}
|
||||
|
||||
blobs := p.repo.Blobs(context.Background())
|
||||
blobs := p.repo.Blobs(nil)
|
||||
|
||||
desc, err := blobs.Stat(context.Background(), di.digest)
|
||||
desc, err := blobs.Stat(nil, di.digest)
|
||||
if err != nil {
|
||||
logrus.Debugf("Error statting layer: %v", err)
|
||||
di.err <- err
|
||||
@@ -150,7 +150,7 @@ func (p *v2Puller) download(di *downloadInfo) {
|
||||
}
|
||||
di.size = desc.Size
|
||||
|
||||
layerDownload, err := blobs.Open(context.Background(), di.digest)
|
||||
layerDownload, err := blobs.Open(nil, di.digest)
|
||||
if err != nil {
|
||||
logrus.Debugf("Error fetching layer: %v", err)
|
||||
di.err <- err
|
||||
@@ -223,9 +223,6 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (verified bool, err error)
|
||||
go func() {
|
||||
if _, err := io.Copy(out, pipeReader); err != nil {
|
||||
logrus.Errorf("error copying from layer download progress reader: %s", err)
|
||||
if err := pipeReader.CloseWithError(err); err != nil {
|
||||
logrus.Errorf("error closing the progress reader: %s", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
defer func() {
|
||||
@@ -235,9 +232,6 @@ func (p *v2Puller) pullV2Tag(tag, taggedName string) (verified bool, err error)
|
||||
// set the error. All successive reads/writes will return with this
|
||||
// error.
|
||||
pipeWriter.CloseWithError(errors.New("download canceled"))
|
||||
} else {
|
||||
// If no error then just close the pipe.
|
||||
pipeWriter.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
+4
-4
@@ -138,7 +138,7 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||
dgst, err := p.graph.GetDigest(layer.ID)
|
||||
switch err {
|
||||
case nil:
|
||||
_, err := p.repo.Blobs(context.Background()).Stat(context.Background(), dgst)
|
||||
_, err := p.repo.Blobs(nil).Stat(nil, dgst)
|
||||
switch err {
|
||||
case nil:
|
||||
exists = true
|
||||
@@ -158,7 +158,7 @@ func (p *v2Pusher) pushV2Tag(tag string) error {
|
||||
// if digest was empty or not saved, or if blob does not exist on the remote repository,
|
||||
// then fetch it.
|
||||
if !exists {
|
||||
if pushDigest, err := p.pushV2Image(p.repo.Blobs(context.Background()), layer); err != nil {
|
||||
if pushDigest, err := p.pushV2Image(p.repo.Blobs(nil), layer); err != nil {
|
||||
return err
|
||||
} else if pushDigest != dgst {
|
||||
// Cache new checksum
|
||||
@@ -226,7 +226,7 @@ func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *image.Image) (d
|
||||
|
||||
// Send the layer
|
||||
logrus.Debugf("rendered layer for %s of [%d] size", img.ID, size)
|
||||
layerUpload, err := bs.Create(context.Background())
|
||||
layerUpload, err := bs.Create(nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -250,7 +250,7 @@ func (p *v2Pusher) pushV2Image(bs distribution.BlobService, img *image.Image) (d
|
||||
}
|
||||
|
||||
desc := distribution.Descriptor{Digest: dgst}
|
||||
if _, err := layerUpload.Commit(context.Background(), desc); err != nil {
|
||||
if _, err := layerUpload.Commit(nil, desc); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
|
||||
+3
-83
@@ -20,70 +20,21 @@ APTDIR=$DOCKER_RELEASE_DIR/apt/repo
|
||||
# setup the apt repo (if it does not exist)
|
||||
mkdir -p "$APTDIR/conf" "$APTDIR/db"
|
||||
|
||||
# supported arches/sections
|
||||
arches=( amd64 i386 )
|
||||
components=( main testing experimental )
|
||||
|
||||
# create/update distributions file
|
||||
if [ ! -f "$APTDIR/conf/distributions" ]; then
|
||||
if [[ ! -f "$APTDIR/conf/distributions" ]]; then
|
||||
for suite in $(exec contrib/reprepro/suites.sh); do
|
||||
cat <<-EOF
|
||||
Origin: Docker
|
||||
Suite: $suite
|
||||
Codename: $suite
|
||||
Architectures: ${arches[*]}
|
||||
Components: ${components[*]}
|
||||
Architectures: amd64 i386
|
||||
Components: main testing experimental
|
||||
Description: Docker APT Repository
|
||||
|
||||
EOF
|
||||
done > "$APTDIR/conf/distributions"
|
||||
fi
|
||||
|
||||
# create/update distributions file
|
||||
if [ ! -f "$APTDIR/conf/apt-ftparchive.conf" ]; then
|
||||
cat <<-EOF > "$APTDIR/conf/apt-ftparchive.conf"
|
||||
Dir {
|
||||
ArchiveDir "${APTDIR}";
|
||||
CacheDir "${APTDIR}/db";
|
||||
};
|
||||
|
||||
Default {
|
||||
Packages::Compress ". gzip bzip2";
|
||||
Sources::Compress ". gzip bzip2";
|
||||
Contents::Compress ". gzip bzip2";
|
||||
};
|
||||
|
||||
TreeDefault {
|
||||
BinCacheDB "packages-\$(SECTION)-\$(ARCH).db";
|
||||
Directory "pool/\$(SECTION)";
|
||||
Packages "\$(DIST)/\$(SECTION)/binary-\$(ARCH)/Packages";
|
||||
SrcDirectory "pool/\$(SECTION)";
|
||||
Sources "\$(DIST)/\$(SECTION)/source/Sources";
|
||||
Contents "\$(DIST)/\$(SECTION)/Contents-\$(ARCH)";
|
||||
FileList "$APTDIR/\$(DIST)/\$(SECTION)/filelist";
|
||||
};
|
||||
EOF
|
||||
|
||||
for suite in $(exec contrib/reprepro/suites.sh); do
|
||||
cat <<-EOF
|
||||
Tree "dists/${suite}" {
|
||||
Sections "main testing experimental";
|
||||
Architectures "${arches[*]}";
|
||||
}
|
||||
|
||||
EOF
|
||||
done >> "$APTDIR/conf/apt-ftparchive.conf"
|
||||
fi
|
||||
|
||||
if [ ! -f "$APTDIR/conf/docker-engine-release.conf" ]; then
|
||||
cat <<-EOF > "$APTDIR/conf/docker-engine-release.conf"
|
||||
APT::FTPArchive::Release::Origin "Docker";
|
||||
APT::FTPArchive::Release::Components "${components[*]}";
|
||||
APT::FTPArchive::Release::Label "Docker APT Repository";
|
||||
APT::FTPArchive::Release::Architectures "${arches[*]}";
|
||||
EOF
|
||||
fi
|
||||
|
||||
# set the component and priority for the version being released
|
||||
component="main"
|
||||
priority=700
|
||||
@@ -116,35 +67,4 @@ for dir in contrib/builder/deb/*/; do
|
||||
reprepro -v --keepunreferencedfiles \
|
||||
-S docker-engine -P "$priority" -C "$component" \
|
||||
-b "$APTDIR" includedeb "$codename" "${DEBFILE[@]}"
|
||||
|
||||
# update the filelist for this codename/component
|
||||
find "$APTDIR/pool/$component" \
|
||||
-name *~${codename#*-}*.deb > "$APTDIR/dists/$codename/$component/filelist"
|
||||
done
|
||||
|
||||
|
||||
# run the apt-ftparchive commands so we can have pinning
|
||||
apt-ftparchive generate "$APTDIR/conf/apt-ftparchive.conf"
|
||||
|
||||
for dir in contrib/builder/deb/*/; do
|
||||
version="$(basename "$dir")"
|
||||
codename="${version//debootstrap-}"
|
||||
|
||||
apt-ftparchive \
|
||||
-o "APT::FTPArchive::Release::Codename=$codename" \
|
||||
-o "APT::FTPArchive::Release::Suite=$codename" \
|
||||
-c "$APTDIR/conf/docker-engine-release.conf" \
|
||||
release \
|
||||
"$APTDIR/dists/$codename" > "$APTDIR/dists/$codename/Release"
|
||||
|
||||
for arch in "${arches[@]}"; do
|
||||
apt-ftparchive \
|
||||
-o "APT::FTPArchive::Release::Codename=$codename" \
|
||||
-o "APT::FTPArchive::Release::Suite=$codename" \
|
||||
-o "APT::FTPArchive::Release::Component=$component" \
|
||||
-o "APT::FTPArchive::Release::Architecture=$arch" \
|
||||
-c "$APTDIR/conf/docker-engine-release.conf" \
|
||||
release \
|
||||
"$APTDIR/dists/$codename/$component/binary-$arch" > "$APTDIR/dists/$codename/$component/binary-$arch/Release"
|
||||
done
|
||||
done
|
||||
|
||||
+5
-5
@@ -21,29 +21,29 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith
|
||||
clone hg code.google.com/p/gosqlite 74691fb6f837
|
||||
|
||||
#get libnetwork packages
|
||||
clone git github.com/docker/libnetwork bc565c2d295067c1a43674a23a473ec6336d7fd4
|
||||
clone git github.com/docker/libnetwork bd3eecc96f3c05a4acef1bedcf74397bc6850d22
|
||||
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
|
||||
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
|
||||
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
|
||||
clone git github.com/hashicorp/serf 7151adcef72687bf95f451a2e0ba15cb19412bf2
|
||||
clone git github.com/docker/libkv 60c7c881345b3c67defc7f93a8297debf041d43c
|
||||
clone git github.com/vishvananda/netns 493029407eeb434d0c2d44e02ea072ff2488d322
|
||||
clone git github.com/vishvananda/netlink 4b5dce31de6d42af5bb9811c6d265472199e0fec
|
||||
clone git github.com/vishvananda/netlink 20397a138846e4d6590e01783ed023ed7e1c38a6
|
||||
clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
|
||||
clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
|
||||
clone git github.com/coreos/go-etcd v2.0.0
|
||||
clone git github.com/hashicorp/consul v0.5.2
|
||||
|
||||
# get graph and distribution packages
|
||||
clone git github.com/docker/distribution ec87e9b6971d831f0eff752ddb54fb64693e51cd # docker/1.8 branch
|
||||
clone git github.com/vbatts/tar-split v0.9.6
|
||||
clone git github.com/docker/distribution 7dc8d4a26b689bd4892f2f2322dbce0b7119d686
|
||||
clone git github.com/vbatts/tar-split v0.9.4
|
||||
|
||||
clone git github.com/docker/notary 8e8122eb5528f621afcd4e2854c47302f17392f7
|
||||
clone git github.com/endophage/gotuf a592b03b28b02bb29bb5878308fb1abed63383b5
|
||||
clone git github.com/tent/canonical-json-go 96e4ba3a7613a1216cbd1badca4efe382adea337
|
||||
clone git github.com/agl/ed25519 d2b94fd789ea21d12fac1a4443dd3a3f79cda72c
|
||||
|
||||
clone git github.com/opencontainers/runc v0.0.2.1 # libcontainer
|
||||
clone git github.com/opencontainers/runc v0.0.2 # libcontainer
|
||||
# libcontainer deps (see src/github.com/docker/libcontainer/update-vendor.sh)
|
||||
clone git github.com/coreos/go-systemd v2
|
||||
clone git github.com/godbus/dbus v2
|
||||
|
||||
@@ -2,10 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -557,23 +554,3 @@ func (s *DockerSuite) TestPsFormatHeaders(c *check.C) {
|
||||
c.Fatalf(`Expected 'NAMES\ntest\n', got %v`, out)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *DockerSuite) TestPsDefaultFormatAndQuiet(c *check.C) {
|
||||
config := `{
|
||||
"psFormat": "{{ .ID }} default"
|
||||
}`
|
||||
d, err := ioutil.TempDir("", "integration-cli-")
|
||||
c.Assert(err, check.IsNil)
|
||||
defer os.RemoveAll(d)
|
||||
|
||||
err = ioutil.WriteFile(filepath.Join(d, "config.json"), []byte(config), 0644)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
out, _ := dockerCmd(c, "run", "--name=test", "-d", "busybox", "top")
|
||||
id := strings.TrimSpace(out)
|
||||
|
||||
out, _ = dockerCmd(c, "--config", d, "ps", "-q")
|
||||
if !strings.HasPrefix(id, strings.TrimSpace(out)) {
|
||||
c.Fatalf("Expected to print only the container id, got %v\n", out)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,40 +369,3 @@ func (s *DockerTrustSuite) TestTrustedPullWithExpiredSnapshot(c *check.C) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Test that pull continues after client has disconnected. #15589
|
||||
func (s *DockerTrustSuite) TestPullClientDisconnect(c *check.C) {
|
||||
testRequires(c, Network)
|
||||
|
||||
repoName := "hello-world:latest"
|
||||
|
||||
dockerCmdWithError(c, "rmi", repoName) // clean just in case
|
||||
|
||||
pullCmd := exec.Command(dockerBinary, "pull", repoName)
|
||||
|
||||
stdout, err := pullCmd.StdoutPipe()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = pullCmd.Start()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
// cancel as soon as we get some output
|
||||
buf := make([]byte, 10)
|
||||
_, err = stdout.Read(buf)
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
err = pullCmd.Process.Kill()
|
||||
c.Assert(err, check.IsNil)
|
||||
|
||||
maxAttempts := 20
|
||||
for i := 0; ; i++ {
|
||||
if _, _, err := dockerCmdWithError(c, "inspect", repoName); err == nil {
|
||||
break
|
||||
}
|
||||
if i >= maxAttempts {
|
||||
c.Fatal("Timeout reached. Image was not pulled after client disconnected.")
|
||||
}
|
||||
time.Sleep(500 * time.Millisecond)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ its own man page which explain usage and arguments.
|
||||
To see the man page for a command run **man docker <command>**.
|
||||
|
||||
# OPTIONS
|
||||
**--help**
|
||||
**-h**, **--help**
|
||||
Print usage statement
|
||||
|
||||
**--api-cors-header**=""
|
||||
|
||||
@@ -38,7 +38,10 @@ static void log_with_errno_init()
|
||||
*/
|
||||
import "C"
|
||||
|
||||
import "unsafe"
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type (
|
||||
CDmTask C.struct_dm_task
|
||||
@@ -184,12 +187,21 @@ func dmTaskGetDepsFct(task *CDmTask) *Deps {
|
||||
if Cdeps == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// golang issue: https://github.com/golang/go/issues/11925
|
||||
hdr := reflect.SliceHeader{
|
||||
Data: uintptr(unsafe.Pointer(uintptr(unsafe.Pointer(Cdeps)) + unsafe.Sizeof(*Cdeps))),
|
||||
Len: int(Cdeps.count),
|
||||
Cap: int(Cdeps.count),
|
||||
}
|
||||
devices := *(*[]C.uint64_t)(unsafe.Pointer(&hdr))
|
||||
|
||||
deps := &Deps{
|
||||
Count: uint32(Cdeps.count),
|
||||
Filler: uint32(Cdeps.filler),
|
||||
}
|
||||
for _, device := range Cdeps.device {
|
||||
deps.Device = append(deps.Device, (uint64)(device))
|
||||
for _, device := range devices {
|
||||
deps.Device = append(deps.Device, uint64(device))
|
||||
}
|
||||
return deps
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -12,12 +13,22 @@ var (
|
||||
|
||||
// file to check to determine Operating System
|
||||
etcOsRelease = "/etc/os-release"
|
||||
|
||||
// used by stateless systems like Clear Linux
|
||||
altEtcOSRelease = "/usr/lib/os-release"
|
||||
)
|
||||
|
||||
func GetOperatingSystem() (string, error) {
|
||||
b, err := ioutil.ReadFile(etcOsRelease)
|
||||
if err != nil {
|
||||
return "", err
|
||||
if _, err2 := os.Stat(altEtcOSRelease); err2 == nil {
|
||||
b, err2 = ioutil.ReadFile(altEtcOSRelease)
|
||||
if err2 != nil {
|
||||
return "", err2
|
||||
}
|
||||
} else {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
if i := bytes.Index(b, []byte("PRETTY_NAME")); i >= 0 {
|
||||
b = b[i+13:]
|
||||
|
||||
@@ -359,18 +359,25 @@ type blobs struct {
|
||||
distribution.BlobDeleter
|
||||
}
|
||||
|
||||
func sanitizeLocation(location, base string) (string, error) {
|
||||
baseURL, err := url.Parse(base)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
func sanitizeLocation(location, source string) (string, error) {
|
||||
locationURL, err := url.Parse(location)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return baseURL.ResolveReference(locationURL).String(), nil
|
||||
if locationURL.Scheme == "" {
|
||||
sourceURL, err := url.Parse(source)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
locationURL = &url.URL{
|
||||
Scheme: sourceURL.Scheme,
|
||||
Host: sourceURL.Host,
|
||||
Path: location,
|
||||
}
|
||||
location = locationURL.String()
|
||||
}
|
||||
return location, nil
|
||||
}
|
||||
|
||||
func (bs *blobs) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
|
||||
|
||||
@@ -19,7 +19,6 @@ import (
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/options"
|
||||
"github.com/docker/libnetwork/portmapper"
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
@@ -90,6 +89,7 @@ type bridgeNetwork struct {
|
||||
config *networkConfiguration
|
||||
endpoints map[types.UUID]*bridgeEndpoint // key: endpoint id
|
||||
portMapper *portmapper.PortMapper
|
||||
veth *netlink.Veth
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
@@ -545,8 +545,6 @@ func (d *driver) getNetworks() []*bridgeNetwork {
|
||||
func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) error {
|
||||
var err error
|
||||
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
// Sanity checks
|
||||
d.Lock()
|
||||
if _, ok := d.networks[id]; ok {
|
||||
@@ -698,8 +696,6 @@ func (d *driver) CreateNetwork(id types.UUID, option map[string]interface{}) err
|
||||
func (d *driver) DeleteNetwork(nid types.UUID) error {
|
||||
var err error
|
||||
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
// Get network handler and remove it from driver
|
||||
d.Lock()
|
||||
n, ok := d.networks[nid]
|
||||
@@ -827,8 +823,6 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||
err error
|
||||
)
|
||||
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
if epInfo == nil {
|
||||
return errors.New("invalid endpoint info passed")
|
||||
}
|
||||
@@ -901,11 +895,13 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||
return err
|
||||
}
|
||||
|
||||
logrus.Warnf("network %v", n)
|
||||
logrus.Warnf("veth %v", n.veth)
|
||||
// Generate and add the interface pipe host <-> sandbox
|
||||
veth := &netlink.Veth{
|
||||
n.veth = &netlink.Veth{
|
||||
LinkAttrs: netlink.LinkAttrs{Name: hostIfName, TxQLen: 0},
|
||||
PeerName: containerIfName}
|
||||
if err = netlink.LinkAdd(veth); err != nil {
|
||||
if err = netlink.LinkAdd(n.veth); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1036,8 +1032,6 @@ func (d *driver) CreateEndpoint(nid, eid types.UUID, epInfo driverapi.EndpointIn
|
||||
func (d *driver) DeleteEndpoint(nid, eid types.UUID) error {
|
||||
var err error
|
||||
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
// Get the network handler and make sure it exists
|
||||
d.Lock()
|
||||
n, ok := d.networks[nid]
|
||||
@@ -1172,13 +1166,16 @@ func (d *driver) EndpointOperInfo(nid, eid types.UUID) (map[string]interface{},
|
||||
m[netlabel.MacAddress] = ep.macAddress
|
||||
}
|
||||
|
||||
// Add details of the bridge
|
||||
m[netlabel.BridgeName] = n.config.BridgeName
|
||||
m[netlabel.BridgePeername] = n.veth.PeerName
|
||||
m[netlabel.BridgeLinkName] = n.veth.LinkAttrs.Name
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// Join method is invoked when a Sandbox is attached to an endpoint.
|
||||
func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinInfo, options map[string]interface{}) error {
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
network, err := d.getNetwork(nid)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1222,8 +1219,6 @@ func (d *driver) Join(nid, eid types.UUID, sboxKey string, jinfo driverapi.JoinI
|
||||
|
||||
// Leave method is invoked when a Sandbox detaches from an endpoint.
|
||||
func (d *driver) Leave(nid, eid types.UUID) error {
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
network, err := d.getNetwork(nid)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/docker/libnetwork/netutils"
|
||||
"github.com/docker/libnetwork/sandbox"
|
||||
"github.com/docker/libnetwork/types"
|
||||
"github.com/vishvananda/netlink"
|
||||
)
|
||||
@@ -22,8 +21,6 @@ func validateID(nid, eid types.UUID) error {
|
||||
}
|
||||
|
||||
func createVethPair() (string, string, error) {
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
// Generate a name for what will be the host side pipe interface
|
||||
name1, err := netutils.GenerateIfaceName(vethPrefix, vethLen)
|
||||
if err != nil {
|
||||
@@ -48,8 +45,6 @@ func createVethPair() (string, string, error) {
|
||||
}
|
||||
|
||||
func createVxlan(vni uint32) (string, error) {
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
name, err := netutils.GenerateIfaceName("vxlan", 7)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("error generating vxlan name: %v", err)
|
||||
@@ -73,8 +68,6 @@ func createVxlan(vni uint32) (string, error) {
|
||||
}
|
||||
|
||||
func deleteVxlan(name string) error {
|
||||
defer sandbox.InitOSContext()()
|
||||
|
||||
link, err := netlink.LinkByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to find vxlan interface with name %s: %v", name, err)
|
||||
|
||||
@@ -24,6 +24,17 @@ const (
|
||||
//EnableIPv6 constant represents enabling IPV6 at network level
|
||||
EnableIPv6 = Prefix + ".enable_ipv6"
|
||||
|
||||
// BridgeName constant represents the name of the network bridge
|
||||
BridgeName = "io.docker.network.bridge.name"
|
||||
|
||||
// BridgePeername constant represents the interface name provided to
|
||||
// the container.
|
||||
BridgePeername = "io.docker.network.bridge.peername"
|
||||
|
||||
// BridgeLinkName constant represents the interface name created on
|
||||
// the host side.
|
||||
BridgeLinkName = "io.docker.network.bridge.linkname"
|
||||
|
||||
// KVProvider constant represents the KV provider backend
|
||||
KVProvider = DriverPrefix + ".kv_provider"
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
package netutils
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var runningInContainer = flag.Bool("incontainer", false, "Indicates if the test is running in a container")
|
||||
|
||||
// IsRunningInContainer returns whether the test is running inside a container.
|
||||
func IsRunningInContainer() bool {
|
||||
return (*runningInContainer)
|
||||
}
|
||||
|
||||
// SetupTestNetNS joins a new network namespace, and returns its associated
|
||||
// teardown function.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// defer SetupTestNetNS(t)()
|
||||
//
|
||||
func SetupTestNetNS(t *testing.T) func() {
|
||||
runtime.LockOSThread()
|
||||
if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
|
||||
t.Fatalf("Failed to enter netns: %v", err)
|
||||
}
|
||||
|
||||
fd, err := syscall.Open("/proc/self/ns/net", syscall.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
t.Fatal("Failed to open netns file")
|
||||
}
|
||||
|
||||
return func() {
|
||||
if err := syscall.Close(fd); err != nil {
|
||||
t.Logf("Warning: netns closing failed (%v)", err)
|
||||
}
|
||||
runtime.UnlockOSThread()
|
||||
}
|
||||
}
|
||||
@@ -26,8 +26,6 @@ var (
|
||||
gpmWg sync.WaitGroup
|
||||
gpmCleanupPeriod = 60 * time.Second
|
||||
gpmChan = make(chan chan struct{})
|
||||
nsOnce sync.Once
|
||||
initNs netns.NsHandle
|
||||
)
|
||||
|
||||
// The networkNamespace type is the linux implementation of the Sandbox
|
||||
@@ -244,37 +242,15 @@ func (n *networkNamespace) InvokeFunc(f func()) error {
|
||||
})
|
||||
}
|
||||
|
||||
func getLink() (string, error) {
|
||||
return os.Readlink(fmt.Sprintf("/proc/%d/task/%d/ns/net", os.Getpid(), syscall.Gettid()))
|
||||
}
|
||||
|
||||
func nsInit() {
|
||||
var err error
|
||||
|
||||
if initNs, err = netns.Get(); err != nil {
|
||||
log.Errorf("could not get initial namespace: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
runtime.LockOSThread()
|
||||
nsOnce.Do(nsInit)
|
||||
if err := netns.Set(initNs); err != nil {
|
||||
linkInfo, linkErr := getLink()
|
||||
if linkErr != nil {
|
||||
linkInfo = linkErr.Error()
|
||||
}
|
||||
|
||||
log.Errorf("failed to set to initial namespace, %v, initns fd %d: %v",
|
||||
linkInfo, initNs, err)
|
||||
}
|
||||
|
||||
return runtime.UnlockOSThread
|
||||
}
|
||||
|
||||
func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD int) error) error {
|
||||
defer InitOSContext()()
|
||||
runtime.LockOSThread()
|
||||
defer runtime.UnlockOSThread()
|
||||
|
||||
origns, err := netns.Get()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer origns.Close()
|
||||
|
||||
f, err := os.OpenFile(path, os.O_RDONLY, 0)
|
||||
if err != nil {
|
||||
@@ -293,10 +269,10 @@ func nsInvoke(path string, prefunc func(nsFD int) error, postfunc func(callerFD
|
||||
if err = netns.Set(netns.NsHandle(nsFD)); err != nil {
|
||||
return err
|
||||
}
|
||||
defer netns.Set(initNs)
|
||||
defer netns.Set(origns)
|
||||
|
||||
// Invoked after the namespace switch.
|
||||
return postfunc(int(initNs))
|
||||
return postfunc(int(origns))
|
||||
}
|
||||
|
||||
func (n *networkNamespace) nsPath() string {
|
||||
|
||||
@@ -21,8 +21,3 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
@@ -21,8 +21,3 @@ func NewSandbox(key string, osCreate bool) (Sandbox, error) {
|
||||
// and waits for it.
|
||||
func GC() {
|
||||
}
|
||||
|
||||
// InitOSContext initializes OS context while configuring network resources
|
||||
func InitOSContext() func() {
|
||||
return func() {}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package fluent
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
"net"
|
||||
"reflect"
|
||||
@@ -34,7 +33,7 @@ type Config struct {
|
||||
|
||||
type Fluent struct {
|
||||
Config
|
||||
conn io.WriteCloser
|
||||
conn net.Conn
|
||||
pending []byte
|
||||
reconnecting bool
|
||||
mu sync.Mutex
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
package fluent
|
||||
|
||||
const Version = "1.0.0"
|
||||
const Version = "0.5.1"
|
||||
|
||||
+1
-1
@@ -236,7 +236,7 @@ func getCgroupData(c *configs.Cgroup, pid int) (*data, error) {
|
||||
}
|
||||
|
||||
func (raw *data) parent(subsystem, mountpoint, src string) (string, error) {
|
||||
initPath, err := cgroups.GetThisCgroupDir(subsystem)
|
||||
initPath, err := cgroups.GetInitCgroupDir(subsystem)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -159,19 +159,17 @@ func (tr *Reader) Next() (*Header, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf []byte
|
||||
var b []byte
|
||||
if tr.RawAccounting {
|
||||
if _, err = tr.rawBytes.Write(realname); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = make([]byte, tr.rawBytes.Len())
|
||||
copy(buf[:], tr.RawBytes())
|
||||
b = tr.RawBytes()
|
||||
}
|
||||
hdr, err := tr.Next()
|
||||
// since the above call to Next() resets the buffer, we need to throw the bytes over
|
||||
if tr.RawAccounting {
|
||||
buf = append(buf, tr.RawBytes()...)
|
||||
if _, err = tr.rawBytes.Write(buf); err != nil {
|
||||
if _, err = tr.rawBytes.Write(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -183,19 +181,17 @@ func (tr *Reader) Next() (*Header, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var buf []byte
|
||||
var b []byte
|
||||
if tr.RawAccounting {
|
||||
if _, err = tr.rawBytes.Write(realname); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buf = make([]byte, tr.rawBytes.Len())
|
||||
copy(buf[:], tr.RawBytes())
|
||||
b = tr.RawBytes()
|
||||
}
|
||||
hdr, err := tr.Next()
|
||||
// since the above call to Next() resets the buffer, we need to throw the bytes over
|
||||
if tr.RawAccounting {
|
||||
buf = append(buf, tr.RawBytes()...)
|
||||
if _, err = tr.rawBytes.Write(buf); err != nil {
|
||||
if _, err = tr.rawBytes.Write(b); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/vbatts/tar-split/tar/storage"
|
||||
)
|
||||
|
||||
// NewOutputTarStream returns an io.ReadCloser that is an assembled tar archive
|
||||
// NewOutputTarStream returns an io.ReadCloser that is an assemble tar archive
|
||||
// stream.
|
||||
//
|
||||
// It takes a storage.FileGetter, for mapping the file payloads that are to be read in,
|
||||
@@ -62,6 +62,7 @@ func NewOutputTarStream(fg storage.FileGetter, up storage.Unpacker) io.ReadClose
|
||||
fh.Close()
|
||||
}
|
||||
}
|
||||
pw.Close()
|
||||
}()
|
||||
return pr
|
||||
}
|
||||
|
||||
+16
-21
@@ -22,8 +22,8 @@ func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io
|
||||
// What to do here... folks will want their own access to the Reader that is
|
||||
// their tar archive stream, but we'll need that same stream to use our
|
||||
// forked 'archive/tar'.
|
||||
// Perhaps do an io.TeeReader that hands back an io.Reader for them to read
|
||||
// from, and we'll MITM the stream to store metadata.
|
||||
// Perhaps do an io.TeeReader that hand back an io.Reader for them to read
|
||||
// from, and we'll mitm the stream to store metadata.
|
||||
// We'll need a storage.FilePutter too ...
|
||||
|
||||
// Another concern, whether to do any storage.FilePutter operations, such that we
|
||||
@@ -32,7 +32,7 @@ func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io
|
||||
// Perhaps we have a DiscardFilePutter that is a bit bucket.
|
||||
|
||||
// we'll return the pipe reader, since TeeReader does not buffer and will
|
||||
// only read what the outputRdr Read's. Since Tar archives have padding on
|
||||
// only read what the outputRdr Read's. Since Tar archive's have padding on
|
||||
// the end, we want to be the one reading the padding, even if the user's
|
||||
// `archive/tar` doesn't care.
|
||||
pR, pW := io.Pipe()
|
||||
@@ -55,15 +55,13 @@ func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io
|
||||
}
|
||||
// even when an EOF is reached, there is often 1024 null bytes on
|
||||
// the end of an archive. Collect them too.
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
_, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
_, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: tr.RawBytes(),
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
break // not return. We need the end of the reader.
|
||||
}
|
||||
@@ -71,15 +69,12 @@ func NewInputTarStream(r io.Reader, p storage.Packer, fp storage.FilePutter) (io
|
||||
break // not return. We need the end of the reader.
|
||||
}
|
||||
|
||||
if b := tr.RawBytes(); len(b) > 0 {
|
||||
_, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: b,
|
||||
})
|
||||
if err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
if _, err := p.AddEntry(storage.Entry{
|
||||
Type: storage.SegmentType,
|
||||
Payload: tr.RawBytes(),
|
||||
}); err != nil {
|
||||
pW.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
var csum []byte
|
||||
|
||||
@@ -5,7 +5,7 @@ Packing and unpacking the Entries of the stream. The types of streams are
|
||||
either segments of raw bytes (for the raw headers and various padding) and for
|
||||
an entry marking a file payload.
|
||||
|
||||
The raw bytes are stored precisely in the packed (marshalled) Entry, whereas
|
||||
The raw bytes are stored precisely in the packed (marshalled) Entry. Where as
|
||||
the file payload marker include the name of the file, size, and crc64 checksum
|
||||
(for basic file integrity).
|
||||
*/
|
||||
|
||||
@@ -19,11 +19,11 @@ const (
|
||||
// SegmentType represents a raw bytes segment from the archive stream. These raw
|
||||
// byte segments consist of the raw headers and various padding.
|
||||
//
|
||||
// Its payload is to be marshalled base64 encoded.
|
||||
// It's payload is to be marshalled base64 encoded.
|
||||
SegmentType
|
||||
)
|
||||
|
||||
// Entry is the structure for packing and unpacking the information read from
|
||||
// Entry is a the structure for packing and unpacking the information read from
|
||||
// the Tar archive.
|
||||
//
|
||||
// FileType Payload checksum is using `hash/crc64` for basic file integrity,
|
||||
@@ -32,8 +32,8 @@ const (
|
||||
// collisions in a sample of 18.2 million, CRC64 had none.
|
||||
type Entry struct {
|
||||
Type Type `json:"type"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
Payload []byte `json:"payload"` // SegmentType stores payload here; FileType stores crc64 checksum here;
|
||||
Name string `json:"name",omitempty`
|
||||
Size int64 `json:"size",omitempty`
|
||||
Payload []byte `json:"payload"` // SegmentType store payload here; FileType store crc64 checksum here;
|
||||
Position int `json:"position"`
|
||||
}
|
||||
|
||||
+13
-11
@@ -5,13 +5,14 @@ import (
|
||||
"errors"
|
||||
"hash/crc64"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// FileGetter is the interface for getting a stream of a file payload,
|
||||
// addressed by name/filename. Presumably, the names will be scoped to relative
|
||||
// file paths.
|
||||
// FileGetter is the interface for getting a stream of a file payload, address
|
||||
// by name/filename. Presumably, the names will be scoped to relative file
|
||||
// paths.
|
||||
type FileGetter interface {
|
||||
// Get returns a stream for the provided file path
|
||||
Get(filename string) (output io.ReadCloser, err error)
|
||||
@@ -59,15 +60,15 @@ func (bfgp bufferFileGetPutter) Get(name string) (io.ReadCloser, error) {
|
||||
}
|
||||
|
||||
func (bfgp *bufferFileGetPutter) Put(name string, r io.Reader) (int64, []byte, error) {
|
||||
crc := crc64.New(CRCTable)
|
||||
buf := bytes.NewBuffer(nil)
|
||||
cw := io.MultiWriter(crc, buf)
|
||||
i, err := io.Copy(cw, r)
|
||||
c := crc64.New(CRCTable)
|
||||
tRdr := io.TeeReader(r, c)
|
||||
b := bytes.NewBuffer([]byte{})
|
||||
i, err := io.Copy(b, tRdr)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
bfgp.files[name] = buf.Bytes()
|
||||
return i, crc.Sum(nil), nil
|
||||
bfgp.files[name] = b.Bytes()
|
||||
return i, c.Sum(nil), nil
|
||||
}
|
||||
|
||||
type readCloserWrapper struct {
|
||||
@@ -76,7 +77,7 @@ type readCloserWrapper struct {
|
||||
|
||||
func (w *readCloserWrapper) Close() error { return nil }
|
||||
|
||||
// NewBufferFileGetPutter is a simple in-memory FileGetPutter
|
||||
// NewBufferFileGetPutter is simple in memory FileGetPutter
|
||||
//
|
||||
// Implication is this is memory intensive...
|
||||
// Probably best for testing or light weight cases.
|
||||
@@ -96,7 +97,8 @@ type bitBucketFilePutter struct {
|
||||
|
||||
func (bbfp *bitBucketFilePutter) Put(name string, r io.Reader) (int64, []byte, error) {
|
||||
c := crc64.New(CRCTable)
|
||||
i, err := io.Copy(c, r)
|
||||
tRdr := io.TeeReader(r, c)
|
||||
i, err := io.Copy(ioutil.Discard, tRdr)
|
||||
return i, c.Sum(nil), err
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// ErrDuplicatePath occurs when a tar archive has more than one entry for the
|
||||
// same file path
|
||||
// ErrDuplicatePath is occured when a tar archive has more than one entry for
|
||||
// the same file path
|
||||
var ErrDuplicatePath = errors.New("duplicates of file paths not supported")
|
||||
|
||||
// Packer describes the methods to pack Entries to a storage destination
|
||||
@@ -65,7 +65,7 @@ func (jup *jsonUnpacker) Next() (*Entry, error) {
|
||||
if _, ok := jup.seen[cName]; ok {
|
||||
return nil, ErrDuplicatePath
|
||||
}
|
||||
jup.seen[cName] = struct{}{}
|
||||
jup.seen[cName] = emptyByte
|
||||
}
|
||||
|
||||
return &e, err
|
||||
@@ -90,7 +90,11 @@ type jsonPacker struct {
|
||||
seen seenNames
|
||||
}
|
||||
|
||||
type seenNames map[string]struct{}
|
||||
type seenNames map[string]byte
|
||||
|
||||
// used in the seenNames map. byte is a uint8, and we'll re-use the same one
|
||||
// for minimalism.
|
||||
const emptyByte byte = 0
|
||||
|
||||
func (jp *jsonPacker) AddEntry(e Entry) (int, error) {
|
||||
// check early for dup name
|
||||
@@ -99,7 +103,7 @@ func (jp *jsonPacker) AddEntry(e Entry) (int, error) {
|
||||
if _, ok := jp.seen[cName]; ok {
|
||||
return -1, ErrDuplicatePath
|
||||
}
|
||||
jp.seen[cName] = struct{}{}
|
||||
jp.seen[cName] = emptyByte
|
||||
}
|
||||
|
||||
e.Position = jp.pos
|
||||
@@ -113,7 +117,7 @@ func (jp *jsonPacker) AddEntry(e Entry) (int, error) {
|
||||
return e.Position, nil
|
||||
}
|
||||
|
||||
// NewJSONPacker provides a Packer that writes each Entry (SegmentType and
|
||||
// NewJSONPacker provides an Packer that writes each Entry (SegmentType and
|
||||
// FileType) as a json document.
|
||||
//
|
||||
// The Entries are delimited by new line.
|
||||
|
||||
@@ -157,7 +157,6 @@ type Vxlan struct {
|
||||
L2miss bool
|
||||
L3miss bool
|
||||
NoAge bool
|
||||
GBP bool
|
||||
Age int
|
||||
Limit int
|
||||
Port int
|
||||
|
||||
+21
-6
@@ -73,7 +73,10 @@ func LinkSetMTU(link Link, mtu int) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = syscall.IFLA_MTU
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
@@ -94,7 +97,10 @@ func LinkSetName(link Link, name string) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = syscall.IFLA_IFNAME
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_IFNAME, []byte(name))
|
||||
@@ -112,7 +118,10 @@ func LinkSetHardwareAddr(link Link, hwaddr net.HardwareAddr) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = syscall.IFLA_ADDRESS
|
||||
req.AddData(msg)
|
||||
|
||||
data := nl.NewRtAttr(syscall.IFLA_ADDRESS, []byte(hwaddr))
|
||||
@@ -142,7 +151,10 @@ func LinkSetMasterByIndex(link Link, masterIndex int) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = syscall.IFLA_MASTER
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
@@ -164,7 +176,10 @@ func LinkSetNsPid(link Link, nspid int) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = syscall.IFLA_NET_NS_PID
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
@@ -186,7 +201,10 @@ func LinkSetNsFd(link Link, fd int) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_UNSPEC)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = nl.IFLA_NET_NS_FD
|
||||
req.AddData(msg)
|
||||
|
||||
b := make([]byte, 4)
|
||||
@@ -248,10 +266,6 @@ func addVxlanAttrs(vxlan *Vxlan, linkInfo *nl.RtAttr) {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L2MISS, boolAttr(vxlan.L2miss))
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_L3MISS, boolAttr(vxlan.L3miss))
|
||||
|
||||
if vxlan.GBP {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_GBP, boolAttr(vxlan.GBP))
|
||||
}
|
||||
|
||||
if vxlan.NoAge {
|
||||
nl.NewRtAttrChild(data, nl.IFLA_VXLAN_AGEING, nl.Uint32Attr(0))
|
||||
} else if vxlan.Age > 0 {
|
||||
@@ -613,7 +627,10 @@ func setProtinfoAttr(link Link, mode bool, attr int) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_SETLINK, syscall.NLM_F_ACK)
|
||||
|
||||
msg := nl.NewIfInfomsg(syscall.AF_BRIDGE)
|
||||
msg.Type = syscall.RTM_SETLINK
|
||||
msg.Flags = syscall.NLM_F_REQUEST
|
||||
msg.Index = int32(base.Index)
|
||||
msg.Change = syscall.IFLA_PROTINFO | syscall.NLA_F_NESTED
|
||||
req.AddData(msg)
|
||||
|
||||
br := nl.NewRtAttr(syscall.IFLA_PROTINFO|syscall.NLA_F_NESTED, nil)
|
||||
@@ -666,8 +683,6 @@ func parseVxlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vxlan.L2miss = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_L3MISS:
|
||||
vxlan.L3miss = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_GBP:
|
||||
vxlan.GBP = int8(datum.Value[0]) != 0
|
||||
case nl.IFLA_VXLAN_AGEING:
|
||||
vxlan.Age = int(native.Uint32(datum.Value[0:4]))
|
||||
vxlan.NoAge = vxlan.Age == 0
|
||||
|
||||
@@ -47,15 +47,7 @@ const (
|
||||
IFLA_VXLAN_PORT
|
||||
IFLA_VXLAN_GROUP6
|
||||
IFLA_VXLAN_LOCAL6
|
||||
IFLA_VXLAN_UDP_CSUM
|
||||
IFLA_VXLAN_UDP_ZERO_CSUM6_TX
|
||||
IFLA_VXLAN_UDP_ZERO_CSUM6_RX
|
||||
IFLA_VXLAN_REMCSUM_TX
|
||||
IFLA_VXLAN_REMCSUM_RX
|
||||
IFLA_VXLAN_GBP
|
||||
IFLA_VXLAN_REMCSUM_NOPARTIAL
|
||||
IFLA_VXLAN_FLOWBASED
|
||||
IFLA_VXLAN_MAX = IFLA_VXLAN_FLOWBASED
|
||||
IFLA_VXLAN_MAX = IFLA_VXLAN_LOCAL6
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -39,9 +39,8 @@ func NativeEndian() binary.ByteOrder {
|
||||
var x uint32 = 0x01020304
|
||||
if *(*byte)(unsafe.Pointer(&x)) == 0x01 {
|
||||
nativeEndian = binary.BigEndian
|
||||
} else {
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
nativeEndian = binary.LittleEndian
|
||||
}
|
||||
return nativeEndian
|
||||
}
|
||||
|
||||
@@ -20,15 +20,6 @@ func NewRtMsg() *RtMsg {
|
||||
}
|
||||
}
|
||||
|
||||
func NewRtDelMsg() *RtMsg {
|
||||
return &RtMsg{
|
||||
RtMsg: syscall.RtMsg{
|
||||
Table: syscall.RT_TABLE_MAIN,
|
||||
Scope: syscall.RT_SCOPE_NOWHERE,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (msg *RtMsg) Len() int {
|
||||
return syscall.SizeofRtMsg
|
||||
}
|
||||
|
||||
@@ -14,21 +14,22 @@ import (
|
||||
// Equivalent to: `ip route add $route`
|
||||
func RouteAdd(route *Route) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_NEWROUTE, syscall.NLM_F_CREATE|syscall.NLM_F_EXCL|syscall.NLM_F_ACK)
|
||||
return routeHandle(route, req, nl.NewRtMsg())
|
||||
return routeHandle(route, req)
|
||||
}
|
||||
|
||||
// RouteAdd will delete a route from the system.
|
||||
// Equivalent to: `ip route del $route`
|
||||
func RouteDel(route *Route) error {
|
||||
req := nl.NewNetlinkRequest(syscall.RTM_DELROUTE, syscall.NLM_F_ACK)
|
||||
return routeHandle(route, req, nl.NewRtDelMsg())
|
||||
return routeHandle(route, req)
|
||||
}
|
||||
|
||||
func routeHandle(route *Route, req *nl.NetlinkRequest, msg *nl.RtMsg) error {
|
||||
func routeHandle(route *Route, req *nl.NetlinkRequest) error {
|
||||
if (route.Dst == nil || route.Dst.IP == nil) && route.Src == nil && route.Gw == nil {
|
||||
return fmt.Errorf("one of Dst.IP, Src, or Gw must not be nil")
|
||||
}
|
||||
|
||||
msg := nl.NewRtMsg()
|
||||
msg.Scope = uint8(route.Scope)
|
||||
family := -1
|
||||
var rtAttrs []*nl.RtAttr
|
||||
|
||||
Reference in New Issue
Block a user