Add functional support for Docker sub commands on Solaris

Signed-off-by: Amit Krishnan <krish.amit@gmail.com>

Signed-off-by: Alexander Morozov <lk4d4@docker.com>
This commit is contained in:
Amit Krishnan 2016-06-07 00:45:21 -07:00 committed by Alexander Morozov
parent c5ceb0f945
commit 934328d8ea
77 changed files with 1572 additions and 571 deletions

View File

@ -137,7 +137,8 @@ ENV DOCKER_CROSSPLATFORMS \
linux/386 linux/arm \
darwin/amd64 \
freebsd/amd64 freebsd/386 freebsd/arm \
windows/amd64 windows/386
windows/amd64 windows/386 \
solaris/amd64
# Dependency for golint
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3

20
Dockerfile.solaris Normal file
View File

@ -0,0 +1,20 @@
# Defines an image that hosts a native Docker build environment for Solaris
# TODO: Improve stub
FROM solaris:latest
# compile and runtime deps
RUN pkg install --accept \
git \
gnu-coreutils \
gnu-make \
gnu-tar \
diagnostic/top \
golang \
library/golang/* \
developer/gcc-*
ENV GOPATH /go/:/usr/lib/gocode/1.5/
ENV DOCKER_CROSSPLATFORMS solaris/amd64
WORKDIR /go/src/github.com/docker/docker
COPY . /go/src/github.com/docker/docker

View File

@ -52,6 +52,11 @@ func notifySystem() {
func (cli *DaemonCli) getPlatformRemoteOptions() []libcontainerd.RemoteOption {
opts := []libcontainerd.RemoteOption{}
if cli.Config.ContainerdAddr != "" {
opts = append(opts, libcontainerd.WithRemoteAddr(cli.Config.ContainerdAddr))
} else {
opts = append(opts, libcontainerd.WithStartDaemon(true))
}
return opts
}

View File

@ -1,13 +1,15 @@
// +build !windows
// +build !windows,!solaris
// TODO: Create new file for Solaris which tests config parameters
// as described in daemon/config_solaris.go
package main
import (
"testing"
"github.com/docker/docker/daemon"
"github.com/docker/docker/pkg/testutil/assert"
"github.com/docker/docker/pkg/testutil/tempfile"
"testing"
)
func TestLoadDaemonCliConfigWithDaemonFlags(t *testing.T) {

View File

@ -0,0 +1,9 @@
package container
import (
"golang.org/x/sys/unix"
)
func detachMounted(path string) error {
return unix.Unmount(path, unix.MNT_DETACH)
}

View File

@ -0,0 +1,13 @@
// +build solaris freebsd
package container
import (
"golang.org/x/sys/unix"
)
func detachMounted(path string) error {
//Solaris and FreeBSD do not support the lazy unmount or MNT_DETACH feature.
// Therefore there are separate definitions for this.
return unix.Unmount(path, 0)
}

View File

@ -1,100 +0,0 @@
// +build solaris
package container
import (
"os"
"path/filepath"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/volume"
)
// Container holds fields specific to the Solaris implementation. See
// CommonContainer for standard fields common to all containers.
type Container struct {
CommonContainer
// fields below here are platform specific.
HostnamePath string
HostsPath string
ResolvConfPath string
}
// ExitStatus provides exit reasons for a container.
type ExitStatus struct {
// The exit code with which the container exited.
ExitCode int
}
// CreateDaemonEnvironment creates a new environment variable slice for this container.
func (container *Container) CreateDaemonEnvironment(_ bool, linkedEnv []string) []string {
return nil
}
func appendNetworkMounts(container *Container, volumeMounts []volume.MountPoint) ([]volume.MountPoint, error) {
return volumeMounts, nil
}
// TrySetNetworkMount attempts to set the network mounts given a provided destination and
// the path to use for it; return true if the given destination was a network mount file
func (container *Container) TrySetNetworkMount(destination string, path string) bool {
return true
}
// NetworkMounts returns the list of network mounts.
func (container *Container) NetworkMounts() []Mount {
var mount []Mount
return mount
}
// CopyImagePathContent copies files in destination to the volume.
func (container *Container) CopyImagePathContent(v volume.Volume, destination string) error {
return nil
}
// UnmountIpcMounts unmount Ipc related mounts.
func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
}
// IpcMounts returns the list of Ipc related mounts.
func (container *Container) IpcMounts() []Mount {
return nil
}
// UpdateContainer updates configuration of a container
func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
return nil
}
// UnmountVolumes explicitly unmounts volumes from the container.
func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
return nil
}
// TmpfsMounts returns the list of tmpfs mounts
func (container *Container) TmpfsMounts() []Mount {
var mounts []Mount
return mounts
}
// cleanResourcePath cleans a resource path and prepares to combine with mnt path
func cleanResourcePath(path string) string {
return filepath.Join(string(os.PathSeparator), path)
}
// BuildHostnameFile writes the container's hostname file.
func (container *Container) BuildHostnameFile() error {
return nil
}
// canMountFS determines if the file system for the container
// can be mounted locally. A no-op on non-Windows platforms
func (container *Container) canMountFS() bool {
return true
}
// EnableServiceDiscoveryOnDefaultNetwork Enable service discovery on default network
func (container *Container) EnableServiceDiscoveryOnDefaultNetwork() bool {
return false
}

View File

@ -1,4 +1,4 @@
// +build linux freebsd
// +build linux freebsd solaris
package container
@ -8,7 +8,6 @@ import (
"os"
"path/filepath"
"strings"
"syscall"
"github.com/Sirupsen/logrus"
containertypes "github.com/docker/docker/api/types/container"
@ -20,6 +19,7 @@ import (
"github.com/docker/docker/utils"
"github.com/docker/docker/volume"
"github.com/opencontainers/runc/libcontainer/label"
"golang.org/x/sys/unix"
)
// DefaultSHMSize is the default size (64MB) of the SHM which will be mounted in the container
@ -200,7 +200,7 @@ func (container *Container) CopyImagePathContent(v volume.Volume, destination st
logrus.Warnf("error while unmounting volume %s: %v", v.Name(), err)
}
}()
if err := label.Relabel(path, container.MountLabel, true); err != nil && err != syscall.ENOTSUP {
if err := label.Relabel(path, container.MountLabel, true); err != nil && err != unix.ENOTSUP {
return err
}
return copyExistingContents(rootfs, path)
@ -320,10 +320,6 @@ func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfi
return nil
}
func detachMounted(path string) error {
return syscall.Unmount(path, syscall.MNT_DETACH)
}
// UnmountVolumes unmounts all volumes
func (container *Container) UnmountVolumes(forceSyscall bool, volumeEventLog func(name, action string, attributes map[string]string)) error {
var (

View File

@ -1,6 +1,8 @@
package container
import "sync"
import (
"sync"
)
// memoryStore implements a Store in memory.
type memoryStore struct {
@ -25,8 +27,9 @@ func (c *memoryStore) Add(id string, cont *Container) {
// Get returns a container from the store by id.
func (c *memoryStore) Get(id string) *Container {
var res *Container
c.RLock()
res := c.s[id]
res = c.s[id]
c.RUnlock()
return res
}

View File

@ -1,4 +1,4 @@
// +build !windows
// +build !windows,!solaris
package main

View File

@ -0,0 +1,4 @@
FROM solaris
EXPOSE 80/tcp
COPY httpserver .
CMD ["./httpserver"]

View File

@ -11,11 +11,22 @@ usage() {
echo >&2 " $mkimg -t someuser/centos:5 rinse --distribution centos-5"
echo >&2 " $mkimg -t someuser/mageia:4 mageia-urpmi --version=4"
echo >&2 " $mkimg -t someuser/mageia:4 mageia-urpmi --version=4 --mirror=http://somemirror/"
echo >&2 " $mkimg -t someuser/solaris solaris"
exit 1
}
scriptDir="$(dirname "$(readlink -f "$BASH_SOURCE")")/mkimage"
os=
os=$(uname -o)
# set up path to gnu tools if solaris
[[ $os == "Solaris" ]] && export PATH=/usr/gnu/bin:$PATH
# TODO check for gnu-tar, gnu-getopt
# TODO requires root/sudo due to some pkg operations. sigh.
[[ $os == "Solaris" && $EUID != "0" ]] && echo >&2 "image create on Solaris requires superuser privilege"
optTemp=$(getopt --options '+d:t:c:hC' --longoptions 'dir:,tag:,compression:,no-compression,help' --name "$mkimg" -- "$@")
eval set -- "$optTemp"
unset optTemp

89
contrib/mkimage/solaris Executable file
View File

@ -0,0 +1,89 @@
#!/usr/bin/env bash
#
# Solaris 12 base image build script.
#
set -e
# TODO add optional package publisher origin
rootfsDir="$1"
shift
# base install
(
set -x
pkg image-create --full --zone \
--facet facet.locale.*=false \
--facet facet.locale.POSIX=true \
--facet facet.doc=false \
--facet facet.doc.*=false \
"$rootfsDir"
pkg -R "$rootfsDir" set-property use-system-repo true
pkg -R "$rootfsDir" set-property flush-content-cache-on-success true
pkg -R "$rootfsDir" install core-os
)
# Lay in stock configuration, set up milestone
# XXX This all may become optional in a base image
(
# faster to build repository database on tmpfs
REPO_DB=/system/volatile/repository.$$
export SVCCFG_REPOSITORY=${REPO_DB}
export SVCCFG_DOOR_PATH=$rootfsDir/system/volatile/tmp_repo_door
# Import base manifests. NOTE These are a combination of basic requirement
# and gleaned from container milestone manifest. They may change.
for m in $rootfsDir/lib/svc/manifest/system/environment.xml \
$rootfsDir/lib/svc/manifest/system/svc/global.xml \
$rootfsDir/lib/svc/manifest/system/svc/restarter.xml \
$rootfsDir/lib/svc/manifest/network/dns/client.xml \
$rootfsDir/lib/svc/manifest/system/name-service/switch.xml \
$rootfsDir/lib/svc/manifest/system/name-service/cache.xml \
$rootfsDir/lib/svc/manifest/milestone/container.xml ; do
svccfg import $m
done
# Apply system layer profile, deleting unnecessary dependencies
svccfg apply $rootfsDir/etc/svc/profile/generic_container.xml
# XXX Even if we keep a repo in the base image, this is definitely optional
svccfg apply $rootfsDir/etc/svc/profile/sysconfig/container_sc.xml
for s in svc:/system/svc/restarter \
svc:/system/environment \
svc:/network/dns/client \
svc:/system/name-service/switch \
svc:/system/name-service/cache \
svc:/system/svc/global \
svc:/milestone/container ;do
svccfg -s $s refresh
done
# now copy the built up repository into the base rootfs
mv $REPO_DB $rootfsDir/etc/svc/repository.db
)
# pkg(1) needs the zoneproxy-client running in the container.
# use a simple wrapper to run it as needed.
# XXX maybe we go back to running this in SMF?
mv "$rootfsDir/usr/bin/pkg" "$rootfsDir/usr/bin/wrapped_pkg"
cat > "$rootfsDir/usr/bin/pkg" <<-'EOF'
#!/bin/sh
#
# THIS FILE CREATED DURING DOCKER BASE IMAGE CREATION
#
# The Solaris base image uses the sysrepo proxy mechanism. The
# IPS client pkg(1) requires the zoneproxy-client to reach the
# remote publisher origins through the host. This wrapper script
# enables and disables the proxy client as needed. This is a
# temporary solution.
/usr/lib/zones/zoneproxy-client -s localhost:1008
PKG_SYSREPO_URL=http://localhost:1008 /usr/bin/wrapped_pkg "$@"
pkill -9 zoneproxy-client
EOF
chmod +x "$rootfsDir/usr/bin/pkg"

View File

@ -0,0 +1,5 @@
// +build solaris
package daemon
const bindMountType = "lofs"

5
daemon/bindmount_unix.go Normal file
View File

@ -0,0 +1,5 @@
// +build linux freebsd
package daemon
const bindMountType = "bind"

View File

@ -1,4 +1,4 @@
// +build !linux
// +build !linux,!solaris
package cluster

View File

@ -0,0 +1,57 @@
package cluster
import (
"bufio"
"fmt"
"net"
"os/exec"
"strings"
)
func (c *Cluster) resolveSystemAddr() (net.IP, error) {
defRouteCmd := "/usr/sbin/ipadm show-addr -p -o addr " +
"`/usr/sbin/route get default | /usr/bin/grep interface | " +
"/usr/bin/awk '{print $2}'`"
out, err := exec.Command("/usr/bin/bash", "-c", defRouteCmd).Output()
if err != nil {
return nil, fmt.Errorf("cannot get default route: %v", err)
}
defInterface := strings.SplitN(string(out), "/", 2)
defInterfaceIP := net.ParseIP(defInterface[0])
return defInterfaceIP, nil
}
func listSystemIPs() []net.IP {
var systemAddrs []net.IP
cmd := exec.Command("/usr/sbin/ipadm", "show-addr", "-p", "-o", "addr")
cmdReader, err := cmd.StdoutPipe()
if err != nil {
return nil
}
if err := cmd.Start(); err != nil {
return nil
}
scanner := bufio.NewScanner(cmdReader)
go func() {
for scanner.Scan() {
text := scanner.Text()
nameAddrPair := strings.SplitN(text, "/", 2)
// Let go of loopback interfaces and docker interfaces
systemAddrs = append(systemAddrs, net.ParseIP(nameAddrPair[0]))
}
}()
if err := scanner.Err(); err != nil {
fmt.Printf("scan underwent err: %+v\n", err)
}
if err := cmd.Wait(); err != nil {
fmt.Printf("run command wait: %+v\n", err)
}
return systemAddrs
}

View File

@ -126,9 +126,9 @@ func (daemon *Daemon) Commit(name string, c *backend.ContainerCommitConfig) (str
return "", err
}
// It is not possible to commit a running container on Windows
if runtime.GOOS == "windows" && container.IsRunning() {
return "", fmt.Errorf("Windows does not support commit of a running container")
// It is not possible to commit a running container on Windows and on Solaris.
if (runtime.GOOS == "windows" || runtime.GOOS == "solaris") && container.IsRunning() {
return "", fmt.Errorf("%+v does not support commit of a running container", runtime.GOOS)
}
if c.Pause && !container.IsPaused() {

View File

@ -3,6 +3,7 @@ package daemon
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
@ -221,6 +222,9 @@ func NewConfig() *Config {
}
func parseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (string, error) {
if runtime.GOOS == "solaris" && (clusterAdvertise != "" || clusterStore != "") {
return "", errors.New("Cluster Advertise Settings not supported on Solaris")
}
if clusterAdvertise == "" {
return "", errDiscoveryDisabled
}

View File

@ -0,0 +1,80 @@
// +build solaris linux freebsd
package daemon
import (
"net"
"github.com/docker/docker/api/types"
"github.com/docker/docker/opts"
runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/spf13/pflag"
)
// CommonUnixConfig defines configuration of a docker daemon that is
// common across Unix platforms.
type CommonUnixConfig struct {
ExecRoot string `json:"exec-root,omitempty"`
ContainerdAddr string `json:"containerd,omitempty"`
Runtimes map[string]types.Runtime `json:"runtimes,omitempty"`
DefaultRuntime string `json:"default-runtime,omitempty"`
}
type commonUnixBridgeConfig struct {
DefaultIP net.IP `json:"ip,omitempty"`
IP string `json:"bip,omitempty"`
DefaultGatewayIPv4 net.IP `json:"default-gateway,omitempty"`
DefaultGatewayIPv6 net.IP `json:"default-gateway-v6,omitempty"`
InterContainerCommunication bool `json:"icc,omitempty"`
}
// InstallCommonUnixFlags adds command-line options to the top-level flag parser for
// the current process that are common across Unix platforms.
func (config *Config) InstallCommonUnixFlags(flags *pflag.FlagSet) {
config.Runtimes = make(map[string]types.Runtime)
flags.StringVarP(&config.SocketGroup, "group", "G", "docker", "Group for the unix socket")
flags.StringVar(&config.bridgeConfig.IP, "bip", "", "Specify network bridge IP")
flags.StringVarP(&config.bridgeConfig.Iface, "bridge", "b", "", "Attach containers to a network bridge")
flags.StringVar(&config.bridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs")
flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv4, ""), "default-gateway", "Container default gateway IPv4 address")
flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv6, ""), "default-gateway-v6", "Container default gateway IPv6 address")
flags.BoolVar(&config.bridgeConfig.InterContainerCommunication, "icc", true, "Enable inter-container communication")
flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), "ip", "Default IP when binding container ports")
flags.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), "add-runtime", "Register an additional OCI compatible runtime")
flags.StringVar(&config.DefaultRuntime, "default-runtime", stockRuntimeName, "Default OCI runtime for containers")
}
// GetRuntime returns the runtime path and arguments for a given
// runtime name
func (config *Config) GetRuntime(name string) *types.Runtime {
config.reloadLock.Lock()
defer config.reloadLock.Unlock()
if rt, ok := config.Runtimes[name]; ok {
return &rt
}
return nil
}
// GetDefaultRuntimeName returns the current default runtime
func (config *Config) GetDefaultRuntimeName() string {
config.reloadLock.Lock()
rt := config.DefaultRuntime
config.reloadLock.Unlock()
return rt
}
// GetAllRuntimes returns a copy of the runtimes map
func (config *Config) GetAllRuntimes() map[string]types.Runtime {
config.reloadLock.Lock()
rts := config.Runtimes
config.reloadLock.Unlock()
return rts
}
// GetExecRoot returns the user configured Exec-root
func (config *Config) GetExecRoot() string {
return config.ExecRoot
}

View File

@ -5,7 +5,7 @@ import (
)
var (
defaultPidFile = "/var/run/docker.pid"
defaultPidFile = "/system/volatile/docker/docker.pid"
defaultGraph = "/var/lib/docker"
defaultExec = "zones"
)
@ -16,14 +16,17 @@ var (
type Config struct {
CommonConfig
// Fields below here are platform specific.
ExecRoot string `json:"exec-root,omitempty"`
// These fields are common to all unix platforms.
CommonUnixConfig
}
// bridgeConfig stores all the bridge driver specific
// configuration.
type bridgeConfig struct {
commonBridgeConfig
// Fields below here are platform specific.
commonUnixBridgeConfig
}
// InstallFlags adds command-line options to the top-level flag parser for
@ -32,14 +35,13 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
// First handle install flags which are consistent cross-platform
config.InstallCommonFlags(flags)
// Then install flags common to unix platforms
config.InstallCommonUnixFlags(flags)
// Then platform-specific install flags
config.attachExperimentalFlags(flags)
}
// GetExecRoot returns the user configured Exec-root
func (config *Config) GetExecRoot() string {
return config.ExecRoot
}
func (config *Config) isSwarmCompatible() error {
return nil
}

View File

@ -3,6 +3,7 @@ package daemon
import (
"io/ioutil"
"os"
"runtime"
"strings"
"testing"
@ -35,6 +36,9 @@ func TestDaemonBrokenConfiguration(t *testing.T) {
}
func TestParseClusterAdvertiseSettings(t *testing.T) {
if runtime.GOOS == "solaris" {
t.Skip("ClusterSettings not supported on Solaris\n")
}
_, err := parseClusterAdvertiseSettings("something", "")
if err != errDiscoveryDisabled {
t.Fatalf("expected discovery disabled error, got %v\n", err)

View File

@ -4,10 +4,7 @@ package daemon
import (
"fmt"
"net"
"github.com/docker/docker/api/types"
"github.com/docker/docker/opts"
runconfigopts "github.com/docker/docker/runconfig/opts"
units "github.com/docker/go-units"
"github.com/spf13/pflag"
@ -25,15 +22,14 @@ var (
type Config struct {
CommonConfig
// These fields are common to all unix platforms.
CommonUnixConfig
// Fields below here are platform specific.
CgroupParent string `json:"cgroup-parent,omitempty"`
ContainerdAddr string `json:"containerd,omitempty"`
EnableSelinuxSupport bool `json:"selinux-enabled,omitempty"`
ExecRoot string `json:"exec-root,omitempty"`
RemappedRoot string `json:"userns-remap,omitempty"`
Ulimits map[string]*units.Ulimit `json:"default-ulimits,omitempty"`
Runtimes map[string]types.Runtime `json:"runtimes,omitempty"`
DefaultRuntime string `json:"default-runtime,omitempty"`
CPURealtimePeriod int64 `json:"cpu-rt-period,omitempty"`
CPURealtimeRuntime int64 `json:"cpu-rt-runtime,omitempty"`
OOMScoreAdjust int `json:"oom-score-adjust,omitempty"`
@ -47,19 +43,17 @@ type Config struct {
type bridgeConfig struct {
commonBridgeConfig
// These fields are common to all unix platforms.
commonUnixBridgeConfig
// Fields below here are platform specific.
EnableIPv6 bool `json:"ipv6,omitempty"`
EnableIPTables bool `json:"iptables,omitempty"`
EnableIPForward bool `json:"ip-forward,omitempty"`
EnableIPMasq bool `json:"ip-masq,omitempty"`
EnableUserlandProxy bool `json:"userland-proxy,omitempty"`
UserlandProxyPath string `json:"userland-proxy-path,omitempty"`
DefaultIP net.IP `json:"ip,omitempty"`
IP string `json:"bip,omitempty"`
FixedCIDRv6 string `json:"fixed-cidr-v6,omitempty"`
DefaultGatewayIPv4 net.IP `json:"default-gateway,omitempty"`
DefaultGatewayIPv6 net.IP `json:"default-gateway-v6,omitempty"`
InterContainerCommunication bool `json:"icc,omitempty"`
EnableIPv6 bool `json:"ipv6,omitempty"`
EnableIPTables bool `json:"iptables,omitempty"`
EnableIPForward bool `json:"ip-forward,omitempty"`
EnableIPMasq bool `json:"ip-masq,omitempty"`
EnableUserlandProxy bool `json:"userland-proxy,omitempty"`
UserlandProxyPath string `json:"userland-proxy-path,omitempty"`
FixedCIDRv6 string `json:"fixed-cidr-v6,omitempty"`
}
// InstallFlags adds flags to the pflag.FlagSet to configure the daemon
@ -67,26 +61,20 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
// First handle install flags which are consistent cross-platform
config.InstallCommonFlags(flags)
// Then install flags common to unix platforms
config.InstallCommonUnixFlags(flags)
config.Ulimits = make(map[string]*units.Ulimit)
config.Runtimes = make(map[string]types.Runtime)
// Then platform-specific install flags
flags.BoolVar(&config.EnableSelinuxSupport, "selinux-enabled", false, "Enable selinux support")
flags.StringVarP(&config.SocketGroup, "group", "G", "docker", "Group for the unix socket")
flags.Var(runconfigopts.NewUlimitOpt(&config.Ulimits), "default-ulimit", "Default ulimits for containers")
flags.BoolVar(&config.bridgeConfig.EnableIPTables, "iptables", true, "Enable addition of iptables rules")
flags.BoolVar(&config.bridgeConfig.EnableIPForward, "ip-forward", true, "Enable net.ipv4.ip_forward")
flags.BoolVar(&config.bridgeConfig.EnableIPMasq, "ip-masq", true, "Enable IP masquerading")
flags.BoolVar(&config.bridgeConfig.EnableIPv6, "ipv6", false, "Enable IPv6 networking")
flags.StringVar(&config.ExecRoot, "exec-root", defaultExecRoot, "Root directory for execution state files")
flags.StringVar(&config.bridgeConfig.IP, "bip", "", "Specify network bridge IP")
flags.StringVarP(&config.bridgeConfig.Iface, "bridge", "b", "", "Attach containers to a network bridge")
flags.StringVar(&config.bridgeConfig.FixedCIDR, "fixed-cidr", "", "IPv4 subnet for fixed IPs")
flags.StringVar(&config.bridgeConfig.FixedCIDRv6, "fixed-cidr-v6", "", "IPv6 subnet for fixed IPs")
flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv4, ""), "default-gateway", "Container default gateway IPv4 address")
flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv6, ""), "default-gateway-v6", "Container default gateway IPv6 address")
flags.BoolVar(&config.bridgeConfig.InterContainerCommunication, "icc", true, "Enable inter-container communication")
flags.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), "ip", "Default IP when binding container ports")
flags.BoolVar(&config.bridgeConfig.EnableUserlandProxy, "userland-proxy", true, "Use userland proxy for loopback traffic")
flags.StringVar(&config.bridgeConfig.UserlandProxyPath, "userland-proxy-path", "", "Path to the userland proxy binary")
flags.BoolVar(&config.EnableCors, "api-enable-cors", false, "Enable CORS headers in the remote API, this is deprecated by --api-cors-header")
@ -95,8 +83,6 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
flags.StringVar(&config.RemappedRoot, "userns-remap", "", "User/Group setting for user namespaces")
flags.StringVar(&config.ContainerdAddr, "containerd", "", "Path to containerd socket")
flags.BoolVar(&config.LiveRestoreEnabled, "live-restore", false, "Enable live restore of docker when containers are still running")
flags.Var(runconfigopts.NewNamedRuntimeOpt("runtimes", &config.Runtimes, stockRuntimeName), "add-runtime", "Register an additional OCI compatible runtime")
flags.StringVar(&config.DefaultRuntime, "default-runtime", stockRuntimeName, "Default OCI runtime for containers")
flags.IntVar(&config.OOMScoreAdjust, "oom-score-adjust", -500, "Set the oom_score_adj for the daemon")
flags.BoolVar(&config.Init, "init", false, "Run an init in the container to forward signals and reap processes")
flags.StringVar(&config.InitPath, "init-path", "", "Path to the docker-init binary")
@ -107,39 +93,6 @@ func (config *Config) InstallFlags(flags *pflag.FlagSet) {
config.attachExperimentalFlags(flags)
}
// GetRuntime returns the runtime path and arguments for a given
// runtime name
func (config *Config) GetRuntime(name string) *types.Runtime {
config.reloadLock.Lock()
defer config.reloadLock.Unlock()
if rt, ok := config.Runtimes[name]; ok {
return &rt
}
return nil
}
// GetDefaultRuntimeName returns the current default runtime
func (config *Config) GetDefaultRuntimeName() string {
config.reloadLock.Lock()
rt := config.DefaultRuntime
config.reloadLock.Unlock()
return rt
}
// GetAllRuntimes returns a copy of the runtimes map
func (config *Config) GetAllRuntimes() map[string]types.Runtime {
config.reloadLock.Lock()
rts := config.Runtimes
config.reloadLock.Unlock()
return rts
}
// GetExecRoot returns the user configured Exec-root
func (config *Config) GetExecRoot() string {
return config.ExecRoot
}
func (config *Config) isSwarmCompatible() error {
if config.ClusterStore != "" || config.ClusterAdvertise != "" {
return fmt.Errorf("--cluster-store and --cluster-advertise daemon configurations are incompatible with swarm mode")

View File

@ -2,25 +2,20 @@
package daemon
import "github.com/docker/docker/container"
import (
"github.com/docker/docker/container"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork"
)
func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]string, error) {
return nil, nil
}
// getSize returns real size & virtual size
func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
return 0, 0
}
func (daemon *Daemon) setupIpcDirs(container *container.Container) error {
return nil
}
func (daemon *Daemon) mountVolumes(container *container.Container) error {
return nil
}
func killProcessDirectly(container *container.Container) error {
return nil
}
@ -30,9 +25,22 @@ func detachMounted(path string) error {
}
func isLinkable(child *container.Container) bool {
// A container is linkable only if it belongs to the default network
_, ok := child.NetworkSettings.Networks[runconfig.DefaultDaemonNetworkMode().NetworkName()]
return ok
}
func enableIPOnPredefinedNetwork() bool {
return false
}
func (daemon *Daemon) isNetworkHotPluggable() bool {
return false
}
func setupPathsAndSandboxOptions(container *container.Container, sboxOptions *[]libnetwork.SandboxOption) error {
return nil
}
func initializeNetworkingPaths(container *container.Container, nc *container.Container) {
}

View File

@ -15,9 +15,7 @@ import (
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/links"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork"
@ -63,39 +61,6 @@ func (daemon *Daemon) setupLinkedContainers(container *container.Container) ([]s
return env, nil
}
// getSize returns the real size & virtual size of the container.
func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
var (
sizeRw, sizeRootfs int64
err error
)
if err := daemon.Mount(container); err != nil {
logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
return sizeRw, sizeRootfs
}
defer daemon.Unmount(container)
sizeRw, err = container.RWLayer.Size()
if err != nil {
logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
daemon.GraphDriverName(), container.ID, err)
// FIXME: GetSize should return an error. Not changing it now in case
// there is a side-effect.
sizeRw = -1
}
if parent := container.RWLayer.Parent(); parent != nil {
sizeRootfs, err = parent.Size()
if err != nil {
sizeRootfs = -1
} else if sizeRw != -1 {
sizeRootfs += sizeRw
}
}
return sizeRw, sizeRootfs
}
func (daemon *Daemon) getIpcContainer(container *container.Container) (*container.Container, error) {
containerID := container.HostConfig.IpcMode.Container()
c, err := daemon.GetContainer(containerID)
@ -174,54 +139,6 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
return nil
}
func (daemon *Daemon) mountVolumes(container *container.Container) error {
mounts, err := daemon.setupMounts(container)
if err != nil {
return err
}
for _, m := range mounts {
dest, err := container.GetResourcePath(m.Destination)
if err != nil {
return err
}
var stat os.FileInfo
stat, err = os.Stat(m.Source)
if err != nil {
return err
}
if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil {
return err
}
opts := "rbind,ro"
if m.Writable {
opts = "rbind,rw"
}
if err := mount.Mount(m.Source, dest, "bind", opts); err != nil {
return err
}
// mountVolumes() seems to be called for temporary mounts
// outside the container. Soon these will be unmounted with
// lazy unmount option and given we have mounted the rbind,
// all the submounts will propagate if these are shared. If
// daemon is running in host namespace and has / as shared
// then these unmounts will propagate and unmount original
// mount as well. So make all these mounts rprivate.
// Do not use propagation property of volume as that should
// apply only when mounting happen inside the container.
if err := mount.MakeRPrivate(dest); err != nil {
return err
}
}
return nil
}
func killProcessDirectly(container *container.Container) error {
if _, err := container.WaitStop(10 * time.Second); err != nil {
// Ensure that we don't kill ourselves

View File

@ -3,11 +3,14 @@ package daemon
import (
"fmt"
"net"
"runtime"
"strings"
"time"
"github.com/pkg/errors"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/errors"
apierrors "github.com/docker/docker/api/errors"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
networktypes "github.com/docker/docker/api/types/network"
@ -78,6 +81,10 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig, managed bool) (
if err != nil {
return nil, err
}
if runtime.GOOS == "solaris" && img.OS != "solaris " {
return nil, errors.New("Platform on which parent image was created is not Solaris")
}
imgID = img.ID()
}
@ -260,14 +267,14 @@ func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingCo
for _, v := range nwConfig.EndpointsConfig {
if v != nil && v.IPAMConfig != nil {
if v.IPAMConfig.IPv4Address != "" && net.ParseIP(v.IPAMConfig.IPv4Address).To4() == nil {
return errors.NewBadRequestError(fmt.Errorf("invalid IPv4 address: %s", v.IPAMConfig.IPv4Address))
return apierrors.NewBadRequestError(fmt.Errorf("invalid IPv4 address: %s", v.IPAMConfig.IPv4Address))
}
if v.IPAMConfig.IPv6Address != "" {
n := net.ParseIP(v.IPAMConfig.IPv6Address)
// if the address is an invalid network address (ParseIP == nil) or if it is
// an IPv4 address (To4() != nil), then it is an invalid IPv6 address
if n == nil || n.To4() != nil {
return errors.NewBadRequestError(fmt.Errorf("invalid IPv6 address: %s", v.IPAMConfig.IPv6Address))
return apierrors.NewBadRequestError(fmt.Errorf("invalid IPv6 address: %s", v.IPAMConfig.IPv6Address))
}
}
}
@ -279,5 +286,5 @@ func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingCo
l = append(l, k)
}
err := fmt.Errorf("Container cannot be connected to network endpoints: %s", strings.Join(l, ", "))
return errors.NewBadRequestError(err)
return apierrors.NewBadRequestError(err)
}

View File

@ -4,7 +4,10 @@ package daemon
import (
"fmt"
"net"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/container"
@ -12,9 +15,17 @@ import (
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/reference"
"github.com/docker/libnetwork"
nwconfig "github.com/docker/libnetwork/config"
"github.com/docker/libnetwork/drivers/solaris/bridge"
"github.com/docker/libnetwork/netlabel"
"github.com/docker/libnetwork/netutils"
lntypes "github.com/docker/libnetwork/types"
"github.com/opencontainers/runc/libcontainer/label"
"github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
//#include <zone.h>
@ -27,12 +38,50 @@ const (
solarisMaxCPUShares = 65535
)
func getMemoryResources(config containertypes.Resources) specs.CappedMemory {
memory := specs.CappedMemory{}
if config.Memory > 0 {
memory.Physical = strconv.FormatInt(config.Memory, 10)
}
if config.MemorySwap != 0 {
memory.Swap = strconv.FormatInt(config.MemorySwap, 10)
}
return memory
}
func getCPUResources(config containertypes.Resources) specs.CappedCPU {
cpu := specs.CappedCPU{}
if config.CpusetCpus != "" {
cpu.Ncpus = config.CpusetCpus
}
return cpu
}
func (daemon *Daemon) cleanupMountsByID(id string) error {
return nil
}
func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
return nil
//Since config.SecurityOpt is specifically defined as a "List of string values to
//customize labels for MLs systems, such as SELinux"
//until we figure out how to map to Trusted Extensions
//this is being disabled for now on Solaris
var (
labelOpts []string
err error
)
if len(config.SecurityOpt) > 0 {
return errors.New("Security options are not supported on Solaris")
}
container.ProcessLabel, container.MountLabel, err = label.InitLabels(labelOpts)
return err
}
func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
@ -67,13 +116,198 @@ func (daemon *Daemon) getCgroupDriver() string {
}
func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
if hostConfig.CPUShares < 0 {
logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, solarisMinCPUShares)
hostConfig.CPUShares = solarisMinCPUShares
} else if hostConfig.CPUShares > solarisMaxCPUShares {
logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, solarisMaxCPUShares)
hostConfig.CPUShares = solarisMaxCPUShares
}
if hostConfig.Memory > 0 && hostConfig.MemorySwap == 0 {
// By default, MemorySwap is set to twice the size of Memory.
hostConfig.MemorySwap = hostConfig.Memory * 2
}
if hostConfig.ShmSize != 0 {
hostConfig.ShmSize = container.DefaultSHMSize
}
if hostConfig.OomKillDisable == nil {
defaultOomKillDisable := false
hostConfig.OomKillDisable = &defaultOomKillDisable
}
return nil
}
// UsingSystemd returns true if cli option includes native.cgroupdriver=systemd
func UsingSystemd(config *Config) bool {
return false
}
// verifyPlatformContainerSettings performs platform-specific validation of the
// hostconfig and config structures.
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
warnings := []string{}
sysInfo := sysinfo.New(true)
// NOTE: We do not enforce a minimum value for swap limits for zones on Solaris and
// therefore we will not do that for Docker container either.
if hostConfig.Memory > 0 && !sysInfo.MemoryLimit {
warnings = append(warnings, "Your kernel does not support memory limit capabilities. Limitation discarded.")
logrus.Warnf("Your kernel does not support memory limit capabilities. Limitation discarded.")
hostConfig.Memory = 0
hostConfig.MemorySwap = -1
}
if hostConfig.Memory > 0 && hostConfig.MemorySwap != -1 && !sysInfo.SwapLimit {
warnings = append(warnings, "Your kernel does not support swap limit capabilities, memory limited without swap.")
logrus.Warnf("Your kernel does not support swap limit capabilities, memory limited without swap.")
hostConfig.MemorySwap = -1
}
if hostConfig.Memory > 0 && hostConfig.MemorySwap > 0 && hostConfig.MemorySwap < hostConfig.Memory {
return warnings, fmt.Errorf("Minimum memoryswap limit should be larger than memory limit, see usage.")
}
// Solaris NOTE: We allow and encourage setting the swap without setting the memory limit.
if hostConfig.MemorySwappiness != nil && *hostConfig.MemorySwappiness != -1 && !sysInfo.MemorySwappiness {
warnings = append(warnings, "Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
logrus.Warnf("Your kernel does not support memory swappiness capabilities, memory swappiness discarded.")
hostConfig.MemorySwappiness = nil
}
if hostConfig.MemoryReservation > 0 && !sysInfo.MemoryReservation {
warnings = append(warnings, "Your kernel does not support memory soft limit capabilities. Limitation discarded.")
logrus.Warnf("Your kernel does not support memory soft limit capabilities. Limitation discarded.")
hostConfig.MemoryReservation = 0
}
if hostConfig.Memory > 0 && hostConfig.MemoryReservation > 0 && hostConfig.Memory < hostConfig.MemoryReservation {
return warnings, fmt.Errorf("Minimum memory limit should be larger than memory reservation limit, see usage.")
}
if hostConfig.KernelMemory > 0 && !sysInfo.KernelMemory {
warnings = append(warnings, "Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
logrus.Warnf("Your kernel does not support kernel memory limit capabilities. Limitation discarded.")
hostConfig.KernelMemory = 0
}
if hostConfig.CPUShares != 0 && !sysInfo.CPUShares {
warnings = append(warnings, "Your kernel does not support CPU shares. Shares discarded.")
logrus.Warnf("Your kernel does not support CPU shares. Shares discarded.")
hostConfig.CPUShares = 0
}
if hostConfig.CPUShares < 0 {
warnings = append(warnings, "Invalid CPUShares value. Must be positive. Discarding.")
logrus.Warnf("Invalid CPUShares value. Must be positive. Discarding.")
hostConfig.CPUQuota = 0
}
if hostConfig.CPUShares > 0 && !sysinfo.IsCPUSharesAvailable() {
warnings = append(warnings, "Global zone default scheduling class not FSS. Discarding shares.")
logrus.Warnf("Global zone default scheduling class not FSS. Discarding shares.")
hostConfig.CPUShares = 0
}
// Solaris NOTE: Linux does not do negative checking for CPUShares and Quota here. But it makes sense to.
if hostConfig.CPUPeriod > 0 && !sysInfo.CPUCfsPeriod {
warnings = append(warnings, "Your kernel does not support CPU cfs period. Period discarded.")
logrus.Warnf("Your kernel does not support CPU cfs period. Period discarded.")
if hostConfig.CPUQuota > 0 {
warnings = append(warnings, "Quota will be applied on default period, not period specified.")
logrus.Warnf("Quota will be applied on default period, not period specified.")
}
hostConfig.CPUPeriod = 0
}
if hostConfig.CPUQuota != 0 && !sysInfo.CPUCfsQuota {
warnings = append(warnings, "Your kernel does not support CPU cfs quota. Quota discarded.")
logrus.Warnf("Your kernel does not support CPU cfs quota. Quota discarded.")
hostConfig.CPUQuota = 0
}
if hostConfig.CPUQuota < 0 {
warnings = append(warnings, "Invalid CPUQuota value. Must be positive. Discarding.")
logrus.Warnf("Invalid CPUQuota value. Must be positive. Discarding.")
hostConfig.CPUQuota = 0
}
if (hostConfig.CpusetCpus != "" || hostConfig.CpusetMems != "") && !sysInfo.Cpuset {
warnings = append(warnings, "Your kernel does not support cpuset. Cpuset discarded.")
logrus.Warnf("Your kernel does not support cpuset. Cpuset discarded.")
hostConfig.CpusetCpus = ""
hostConfig.CpusetMems = ""
}
cpusAvailable, err := sysInfo.IsCpusetCpusAvailable(hostConfig.CpusetCpus)
if err != nil {
return warnings, fmt.Errorf("Invalid value %s for cpuset cpus.", hostConfig.CpusetCpus)
}
if !cpusAvailable {
return warnings, fmt.Errorf("Requested CPUs are not available - requested %s, available: %s.", hostConfig.CpusetCpus, sysInfo.Cpus)
}
memsAvailable, err := sysInfo.IsCpusetMemsAvailable(hostConfig.CpusetMems)
if err != nil {
return warnings, fmt.Errorf("Invalid value %s for cpuset mems.", hostConfig.CpusetMems)
}
if !memsAvailable {
return warnings, fmt.Errorf("Requested memory nodes are not available - requested %s, available: %s.", hostConfig.CpusetMems, sysInfo.Mems)
}
if hostConfig.BlkioWeight > 0 && !sysInfo.BlkioWeight {
warnings = append(warnings, "Your kernel does not support Block I/O weight. Weight discarded.")
logrus.Warnf("Your kernel does not support Block I/O weight. Weight discarded.")
hostConfig.BlkioWeight = 0
}
if hostConfig.OomKillDisable != nil && !sysInfo.OomKillDisable {
*hostConfig.OomKillDisable = false
// Don't warn; this is the default setting but only applicable to Linux
}
if sysInfo.IPv4ForwardingDisabled {
warnings = append(warnings, "IPv4 forwarding is disabled. Networking will not work.")
logrus.Warnf("IPv4 forwarding is disabled. Networking will not work")
}
// Solaris NOTE: We do not allow setting Linux specific options, so check and warn for all of them.
if hostConfig.CapAdd != nil || hostConfig.CapDrop != nil {
warnings = append(warnings, "Adding or dropping kernel capabilities unsupported on Solaris.Discarding capabilities lists.")
logrus.Warnf("Adding or dropping kernel capabilities unsupported on Solaris.Discarding capabilities lists.")
hostConfig.CapAdd = nil
hostConfig.CapDrop = nil
}
if hostConfig.GroupAdd != nil {
warnings = append(warnings, "Additional groups unsupported on Solaris.Discarding groups lists.")
logrus.Warnf("Additional groups unsupported on Solaris.Discarding groups lists.")
hostConfig.GroupAdd = nil
}
if hostConfig.IpcMode != "" {
warnings = append(warnings, "IPC namespace assignment unsupported on Solaris.Discarding IPC setting.")
logrus.Warnf("IPC namespace assignment unsupported on Solaris.Discarding IPC setting.")
hostConfig.IpcMode = ""
}
if hostConfig.PidMode != "" {
warnings = append(warnings, "PID namespace setting unsupported on Solaris. Running container in host PID namespace.")
logrus.Warnf("PID namespace setting unsupported on Solaris. Running container in host PID namespace.")
hostConfig.PidMode = ""
}
if hostConfig.Privileged {
warnings = append(warnings, "Privileged mode unsupported on Solaris. Discarding privileged mode setting.")
logrus.Warnf("Privileged mode unsupported on Solaris. Discarding privileged mode setting.")
hostConfig.Privileged = false
}
if hostConfig.UTSMode != "" {
warnings = append(warnings, "UTS namespace assignment unsupported on Solaris.Discarding UTS setting.")
logrus.Warnf("UTS namespace assignment unsupported on Solaris.Discarding UTS setting.")
hostConfig.UTSMode = ""
}
if hostConfig.CgroupParent != "" {
warnings = append(warnings, "Specifying Cgroup parent unsupported on Solaris. Discarding cgroup parent setting.")
logrus.Warnf("Specifying Cgroup parent unsupported on Solaris. Discarding cgroup parent setting.")
hostConfig.CgroupParent = ""
}
if hostConfig.Ulimits != nil {
warnings = append(warnings, "Specifying ulimits unsupported on Solaris. Discarding ulimits setting.")
logrus.Warnf("Specifying ulimits unsupported on Solaris. Discarding ulimits setting.")
hostConfig.Ulimits = nil
}
return warnings, nil
}
@ -84,6 +318,16 @@ func (daemon *Daemon) platformReload(config *Config) map[string]string {
// verifyDaemonSettings performs validation of daemon config struct
func verifyDaemonSettings(config *Config) error {
if config.DefaultRuntime == "" {
config.DefaultRuntime = stockRuntimeName
}
if config.Runtimes == nil {
config.Runtimes = make(map[string]types.Runtime)
}
stockRuntimeOpts := []string{}
config.Runtimes[stockRuntimeName] = types.Runtime{Path: DefaultRuntimeBinary, Args: stockRuntimeOpts}
// checkSystem validates platform-specific requirements
return nil
}
@ -119,7 +363,120 @@ func configureKernelSecuritySupport(config *Config, driverName string) error {
}
func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
return nil, nil
netOptions, err := daemon.networkOptions(config, daemon.PluginStore, activeSandboxes)
if err != nil {
return nil, err
}
controller, err := libnetwork.New(netOptions...)
if err != nil {
return nil, fmt.Errorf("error obtaining controller instance: %v", err)
}
// Initialize default network on "null"
if _, err := controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false)); err != nil {
return nil, fmt.Errorf("Error creating default 'null' network: %v", err)
}
if !config.DisableBridge {
// Initialize default driver "bridge"
if err := initBridgeDriver(controller, config); err != nil {
return nil, err
}
}
return controller, nil
}
func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
if n, err := controller.NetworkByName("bridge"); err == nil {
if err = n.Delete(); err != nil {
return fmt.Errorf("could not delete the default bridge network: %v", err)
}
}
bridgeName := bridge.DefaultBridgeName
if config.bridgeConfig.Iface != "" {
bridgeName = config.bridgeConfig.Iface
}
netOption := map[string]string{
bridge.BridgeName: bridgeName,
bridge.DefaultBridge: strconv.FormatBool(true),
netlabel.DriverMTU: strconv.Itoa(config.Mtu),
bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication),
}
// --ip processing
if config.bridgeConfig.DefaultIP != nil {
netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String()
}
var ipamV4Conf *libnetwork.IpamConf
ipamV4Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
nwList, _, err := netutils.ElectInterfaceAddresses(bridgeName)
if err != nil {
return errors.Wrap(err, "list bridge addresses failed")
}
nw := nwList[0]
if len(nwList) > 1 && config.bridgeConfig.FixedCIDR != "" {
_, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
if err != nil {
return errors.Wrap(err, "parse CIDR failed")
}
// Iterate through in case there are multiple addresses for the bridge
for _, entry := range nwList {
if fCIDR.Contains(entry.IP) {
nw = entry
break
}
}
}
ipamV4Conf.PreferredPool = lntypes.GetIPNetCanonical(nw).String()
hip, _ := lntypes.GetHostPartIP(nw.IP, nw.Mask)
if hip.IsGlobalUnicast() {
ipamV4Conf.Gateway = nw.IP.String()
}
if config.bridgeConfig.IP != "" {
ipamV4Conf.PreferredPool = config.bridgeConfig.IP
ip, _, err := net.ParseCIDR(config.bridgeConfig.IP)
if err != nil {
return err
}
ipamV4Conf.Gateway = ip.String()
} else if bridgeName == bridge.DefaultBridgeName && ipamV4Conf.PreferredPool != "" {
logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
}
if config.bridgeConfig.FixedCIDR != "" {
_, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
if err != nil {
return err
}
ipamV4Conf.SubPool = fCIDR.String()
}
if config.bridgeConfig.DefaultGatewayIPv4 != nil {
ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String()
}
v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
v6Conf := []*libnetwork.IpamConf{}
// Initialize default network on "bridge" with the same name
_, err = controller.NewNetwork("bridge", "bridge", "",
libnetwork.NetworkOptionDriverOpts(netOption),
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
libnetwork.NetworkOptionDeferIPv6Alloc(false))
if err != nil {
return fmt.Errorf("Error creating default 'bridge' network: %v", err)
}
return nil
}
// registerLinks sets up links between containers and writes the
@ -135,7 +492,7 @@ func (daemon *Daemon) cleanupMounts() error {
// conditionalMountOnStart is a platform specific helper function during the
// container start to call mount.
func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
return nil
return daemon.Mount(container)
}
// conditionalUnmountOnCleanup is a platform specific helper function called
@ -171,13 +528,6 @@ func setupDaemonProcess(config *Config) error {
return nil
}
// verifyVolumesInfo is a no-op on solaris.
// This is called during daemon initialization to migrate volumes from pre-1.7.
// Solaris was not supported on pre-1.7 daemons.
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
return nil
}
func (daemon *Daemon) setupSeccompProfile() error {
return nil
}

View File

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

View File

@ -1,4 +1,4 @@
// +build !windows
// +build !windows,!solaris
package daemon

41
daemon/getsize_unix.go Normal file
View File

@ -0,0 +1,41 @@
// +build linux freebsd solaris
package daemon
import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
)
// getSize returns the real size & virtual size of the container.
func (daemon *Daemon) getSize(container *container.Container) (int64, int64) {
var (
sizeRw, sizeRootfs int64
err error
)
if err := daemon.Mount(container); err != nil {
logrus.Errorf("Failed to compute size of container rootfs %s: %s", container.ID, err)
return sizeRw, sizeRootfs
}
defer daemon.Unmount(container)
sizeRw, err = container.RWLayer.Size()
if err != nil {
logrus.Errorf("Driver %s couldn't return diff size of container %s: %s",
daemon.GraphDriverName(), container.ID, err)
// FIXME: GetSize should return an error. Not changing it now in case
// there is a side-effect.
sizeRw = -1
}
if parent := container.RWLayer.Parent(); parent != nil {
sizeRootfs, err = parent.Size()
if err != nil {
sizeRootfs = -1
} else if sizeRw != -1 {
sizeRootfs += sizeRw
}
}
return sizeRw, sizeRootfs
}

View File

@ -20,6 +20,7 @@ import (
"unsafe"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/mount"
)
const (
@ -44,6 +45,37 @@ func GetFSMagic(rootpath string) (FsMagic, error) {
return 0, nil
}
type fsChecker struct {
t FsMagic
}
func (c *fsChecker) IsMounted(path string) bool {
m, _ := Mounted(c.t, path)
return m
}
// NewFsChecker returns a checker configured for the provied FsMagic
func NewFsChecker(t FsMagic) Checker {
return &fsChecker{
t: t,
}
}
// NewDefaultChecker returns a check that parses /proc/mountinfo to check
// if the specified path is mounted.
// No-op on Solaris.
func NewDefaultChecker() Checker {
return &defaultChecker{}
}
type defaultChecker struct {
}
func (c *defaultChecker) IsMounted(path string) bool {
m, _ := mount.Mounted(path)
return m
}
// Mounted checks if the given path is mounted as the fs type
//Solaris supports only ZFS for now
func Mounted(fsType FsMagic, mountPath string) (bool, error) {

View File

@ -1,4 +1,4 @@
// +build linux freebsd
// +build linux freebsd solaris
package graphtest

View File

@ -3,6 +3,7 @@ package daemon
import (
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/backend"
"github.com/docker/docker/api/types/versions/v1p19"
"github.com/docker/docker/container"
"github.com/docker/docker/daemon/exec"
)
@ -13,8 +14,8 @@ func setPlatformSpecificContainerFields(container *container.Container, contJSON
}
// containerInspectPre120 get containers for pre 1.20 APIs.
func (daemon *Daemon) containerInspectPre120(name string) (*types.ContainerJSON, error) {
return daemon.containerInspectCurrent(name, false)
func (daemon *Daemon) containerInspectPre120(name string) (*v1p19.ContainerJSON, error) {
return &v1p19.ContainerJSON{}, nil
}
func addMountPoints(container *container.Container) []types.MountPoint {

View File

@ -3,17 +3,19 @@ package daemon
import (
"fmt"
"net"
"runtime"
"sort"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/errors"
apierrors "github.com/docker/docker/api/errors"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/network"
clustertypes "github.com/docker/docker/daemon/cluster/provider"
"github.com/docker/docker/runconfig"
"github.com/docker/libnetwork"
networktypes "github.com/docker/libnetwork/types"
"github.com/pkg/errors"
"golang.org/x/net/context"
)
@ -236,7 +238,7 @@ func (daemon *Daemon) createNetwork(create types.NetworkCreateRequest, id string
if runconfig.IsPreDefinedNetwork(create.Name) && !agent {
err := fmt.Errorf("%s is a pre-defined network and cannot be created", create.Name)
return nil, errors.NewRequestForbiddenError(err)
return nil, apierrors.NewRequestForbiddenError(err)
}
var warning string
@ -336,6 +338,9 @@ func (daemon *Daemon) UpdateContainerServiceConfig(containerName string, service
// network. If either cannot be found, an err is returned. If the
// network cannot be set up, an err is returned.
func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *network.EndpointSettings) error {
if runtime.GOOS == "solaris" {
return errors.New("docker network connect is unsupported on Solaris platform")
}
container, err := daemon.GetContainer(containerName)
if err != nil {
return err
@ -346,6 +351,9 @@ func (daemon *Daemon) ConnectContainerToNetwork(containerName, networkName strin
// DisconnectContainerFromNetwork disconnects the given container from
// the given network. If either cannot be found, an err is returned.
func (daemon *Daemon) DisconnectContainerFromNetwork(containerName string, networkName string, force bool) error {
if runtime.GOOS == "solaris" {
return errors.New("docker network disconnect is unsupported on Solaris platform")
}
container, err := daemon.GetContainer(containerName)
if err != nil {
if force {
@ -401,7 +409,7 @@ func (daemon *Daemon) deleteNetwork(networkID string, dynamic bool) error {
if runconfig.IsPreDefinedNetwork(nw.Name()) && !dynamic {
err := fmt.Errorf("%s is a pre-defined network and cannot be removed", nw.Name())
return errors.NewRequestForbiddenError(err)
return apierrors.NewRequestForbiddenError(err)
}
if err := nw.Delete(); err != nil {

View File

@ -1,14 +1,183 @@
package daemon
import (
"fmt"
"path/filepath"
"sort"
"strconv"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/container"
"github.com/docker/docker/oci"
"github.com/docker/libnetwork"
"github.com/opencontainers/runtime-spec/specs-go"
)
func setResources(s *specs.Spec, r containertypes.Resources) error {
mem := getMemoryResources(r)
s.Solaris.CappedMemory = &mem
capCPU := getCPUResources(r)
s.Solaris.CappedCPU = &capCPU
return nil
}
func setUser(s *specs.Spec, c *container.Container) error {
uid, gid, additionalGids, err := getUser(c, c.Config.User)
if err != nil {
return err
}
s.Process.User.UID = uid
s.Process.User.GID = gid
s.Process.User.AdditionalGids = additionalGids
return nil
}
func getUser(c *container.Container, username string) (uint32, uint32, []uint32, error) {
return 0, 0, nil, nil
}
func (daemon *Daemon) getRunzAnet(ep libnetwork.Endpoint) (specs.Anet, error) {
var (
linkName string
lowerLink string
defRouter string
)
epInfo := ep.Info()
if epInfo == nil {
return specs.Anet{}, fmt.Errorf("invalid endpoint")
}
nw, err := daemon.GetNetworkByName(ep.Network())
if err != nil {
return specs.Anet{}, fmt.Errorf("Failed to get network %s: %v", ep.Network(), err)
}
// Evaluate default router, linkname and lowerlink for interface endpoint
switch nw.Type() {
case "bridge":
defRouter = epInfo.Gateway().String()
linkName = "net0" // Should always be net0 for a container
// TODO We construct lowerlink here exactly as done for solaris bridge
// initialization. Need modular code to reuse.
options := nw.Info().DriverOptions()
nwName := options["com.docker.network.bridge.name"]
lastChar := nwName[len(nwName)-1:]
if _, err = strconv.Atoi(lastChar); err != nil {
lowerLink = nwName + "_0"
} else {
lowerLink = nwName
}
case "overlay":
defRouter = ""
linkName = "net1"
// TODO Follows generateVxlanName() in solaris overlay.
id := nw.ID()
if len(nw.ID()) > 12 {
id = nw.ID()[:12]
}
lowerLink = "vx_" + id + "_0"
}
runzanet := specs.Anet{
Linkname: linkName,
Lowerlink: lowerLink,
Allowedaddr: epInfo.Iface().Address().String(),
Configallowedaddr: "true",
Defrouter: defRouter,
Linkprotection: "mac-nospoof, ip-nospoof",
Macaddress: epInfo.Iface().MacAddress().String(),
}
return runzanet, nil
}
func (daemon *Daemon) setNetworkInterface(s *specs.Spec, c *container.Container) error {
var anets []specs.Anet
sb, err := daemon.netController.SandboxByID(c.NetworkSettings.SandboxID)
if err != nil {
return fmt.Errorf("Could not obtain sandbox for container")
}
// Populate interfaces required for each endpoint
for _, ep := range sb.Endpoints() {
runzanet, err := daemon.getRunzAnet(ep)
if err != nil {
return fmt.Errorf("Failed to get interface information for endpoint %d: %v", ep.ID(), err)
}
anets = append(anets, runzanet)
}
s.Solaris.Anet = anets
if anets != nil {
s.Solaris.Milestone = "svc:/milestone/container:default"
}
return nil
}
func (daemon *Daemon) populateCommonSpec(s *specs.Spec, c *container.Container) error {
linkedEnv, err := daemon.setupLinkedContainers(c)
if err != nil {
return err
}
s.Root = specs.Root{
Path: filepath.Dir(c.BaseFS),
Readonly: c.HostConfig.ReadonlyRootfs,
}
rootUID, rootGID := daemon.GetRemappedUIDGID()
if err := c.SetupWorkingDirectory(rootUID, rootGID); err != nil {
return err
}
cwd := c.Config.WorkingDir
s.Process.Args = append([]string{c.Path}, c.Args...)
s.Process.Cwd = cwd
s.Process.Env = c.CreateDaemonEnvironment(c.Config.Tty, linkedEnv)
s.Process.Terminal = c.Config.Tty
s.Hostname = c.FullHostname()
return nil
}
func (daemon *Daemon) createSpec(c *container.Container) (*specs.Spec, error) {
s := oci.DefaultSpec()
if err := daemon.populateCommonSpec(&s, c); err != nil {
return nil, err
}
if err := setResources(&s, c.HostConfig.Resources); err != nil {
return nil, fmt.Errorf("runtime spec resources: %v", err)
}
if err := setUser(&s, c); err != nil {
return nil, fmt.Errorf("spec user: %v", err)
}
if err := daemon.setNetworkInterface(&s, c); err != nil {
return nil, err
}
if err := daemon.setupIpcDirs(c); err != nil {
return nil, err
}
ms, err := daemon.setupMounts(c)
if err != nil {
return nil, err
}
ms = append(ms, c.IpcMounts()...)
tmpfsMounts, err := c.TmpfsMounts()
if err != nil {
return nil, err
}
ms = append(ms, tmpfsMounts...)
sort.Sort(mounts(ms))
return (*specs.Spec)(&s), nil
}

View File

@ -11,7 +11,7 @@ import (
"google.golang.org/grpc"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api/errors"
apierrors "github.com/docker/docker/api/errors"
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/container"
@ -21,7 +21,7 @@ import (
// ContainerStart starts a container.
func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.HostConfig, validateHostname bool, checkpoint string, checkpointDir string) error {
if checkpoint != "" && !daemon.HasExperimental() {
return errors.NewBadRequestError(fmt.Errorf("checkpoint is only supported in experimental mode"))
return apierrors.NewBadRequestError(fmt.Errorf("checkpoint is only supported in experimental mode"))
}
container, err := daemon.GetContainer(name)
@ -35,7 +35,7 @@ func (daemon *Daemon) ContainerStart(name string, hostConfig *containertypes.Hos
if container.IsRunning() {
err := fmt.Errorf("Container already started")
return errors.NewErrorWithStatusCode(err, http.StatusNotModified)
return apierrors.NewErrorWithStatusCode(err, http.StatusNotModified)
}
// Windows does not have the backwards compatibility issue here.

View File

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

View File

@ -3,6 +3,7 @@ package daemon
import (
"encoding/json"
"errors"
"fmt"
"runtime"
"time"
@ -19,6 +20,9 @@ import (
// ContainerStats writes information about the container to the stream
// given in the config object.
func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, config *backend.ContainerStatsConfig) error {
if runtime.GOOS == "solaris" {
return fmt.Errorf("%+v does not support stats", runtime.GOOS)
}
// Remote API version (used for backwards compatibility)
apiVersion := config.Version

View File

@ -1,5 +1,7 @@
// +build !windows
// TODO(amitkris): We need to split this file for solaris.
package daemon
import (
@ -11,6 +13,8 @@ import (
"strings"
"github.com/docker/docker/container"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
"github.com/docker/docker/volume/local"
@ -165,3 +169,50 @@ func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
}
return nil
}
func (daemon *Daemon) mountVolumes(container *container.Container) error {
mounts, err := daemon.setupMounts(container)
if err != nil {
return err
}
for _, m := range mounts {
dest, err := container.GetResourcePath(m.Destination)
if err != nil {
return err
}
var stat os.FileInfo
stat, err = os.Stat(m.Source)
if err != nil {
return err
}
if err = fileutils.CreateIfNotExists(dest, stat.IsDir()); err != nil {
return err
}
opts := "rbind,ro"
if m.Writable {
opts = "rbind,rw"
}
if err := mount.Mount(m.Source, dest, bindMountType, opts); err != nil {
return err
}
// mountVolumes() seems to be called for temporary mounts
// outside the container. Soon these will be unmounted with
// lazy unmount option and given we have mounted the rbind,
// all the submounts will propagate if these are shared. If
// daemon is running in host namespace and has / as shared
// then these unmounts will propagate and unmount original
// mount as well. So make all these mounts rprivate.
// Do not use propagation property of volume as that should
// apply only when mounting happen inside the container.
if err := mount.MakeRPrivate(dest); err != nil {
return err
}
}
return nil
}

View File

@ -56,6 +56,9 @@ case "$PACKAGE_ARCH" in
windows)
DOCKERFILE='Dockerfile.windows'
;;
solaris)
DOCKERFILE='Dockerfile.solaris'
;;
esac
;;
*)

View File

@ -29,15 +29,18 @@ for platform in $DOCKER_CROSSPLATFORMS; do
export GOOS=${platform%/*}
export GOARCH=${platform##*/}
if [ -z "${daemonSupporting[$platform]}" ]; then
# we just need a simple client for these platforms
export LDFLAGS_STATIC_DOCKER=""
# remove the "daemon" build tag from platforms that aren't supported
export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" )
source "${MAKEDIR}/binary-client"
else
source "${MAKEDIR}/binary-client"
source "${MAKEDIR}/binary-daemon"
if [ "$GOOS" != "solaris" ]; then
# TODO. Solaris cannot be cross build because of CGO calls.
if [ -z "${daemonSupporting[$platform]}" ]; then
# we just need a simple client for these platforms
export LDFLAGS_STATIC_DOCKER=""
# remove the "daemon" build tag from platforms that aren't supported
export BUILDFLAGS=( "${ORIG_BUILDFLAGS[@]/ daemon/}" )
source "${MAKEDIR}/binary-client"
else
source "${MAKEDIR}/binary-client"
source "${MAKEDIR}/binary-daemon"
fi
fi
)
done

View File

@ -25,15 +25,30 @@ bundle_test_unit() {
else
TEST_PATH=./${TESTDIRS}
fi
pkg_list=$(go list -e \
-f '{{if ne .Name "github.com/docker/docker"}}
{{.ImportPath}}
{{end}}' \
"${BUILDFLAGS[@]}" $TEST_PATH \
| grep github.com/docker/docker \
| grep -v github.com/docker/docker/vendor \
| grep -v github.com/docker/docker/man \
| grep -v github.com/docker/docker/integration-cli)
if [ "$(go env GOHOSTOS)" = 'solaris' ]; then
pkg_list=$(go list -e \
-f '{{if ne .Name "github.com/docker/docker"}}
{{.ImportPath}}
{{end}}' \
"${BUILDFLAGS[@]}" $TEST_PATH \
| grep github.com/docker/docker \
| grep -v github.com/docker/docker/vendor \
| grep -v github.com/docker/docker/daemon/graphdriver \
| grep -v github.com/docker/docker/man \
| grep -v github.com/docker/docker/integration-cli)
else
pkg_list=$(go list -e \
-f '{{if ne .Name "github.com/docker/docker"}}
{{.ImportPath}}
{{end}}' \
"${BUILDFLAGS[@]}" $TEST_PATH \
| grep github.com/docker/docker \
| grep -v github.com/docker/docker/vendor \
| grep -v github.com/docker/docker/man \
| grep -v github.com/docker/docker/integration-cli)
fi
go test -cover -ldflags "$LDFLAGS" "${BUILDFLAGS[@]}" $TESTFLAGS $pkg_list
}

View File

@ -25,6 +25,9 @@ for d in "$CROSS/"*/*; do
# if windows use a zip, not tgz
BUNDLE_EXTENSION=".zip"
IS_TAR="false"
elif [ "$GOOS" == "solaris" ]; then
# Solaris bypasses cross due to CGO issues.
continue
else
BUNDLE_EXTENSION=".tgz"
IS_TAR="true"

View File

@ -1,10 +1,8 @@
package libcontainerd
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"syscall"
@ -12,7 +10,6 @@ import (
"github.com/Sirupsen/logrus"
containerd "github.com/docker/containerd/api/grpc/types"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/ioutils"
"github.com/docker/docker/pkg/mount"
"github.com/golang/protobuf/ptypes"
@ -124,87 +121,6 @@ func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendly
return int(resp.SystemPid), nil
}
func (clnt *client) prepareBundleDir(uid, gid int) (string, error) {
root, err := filepath.Abs(clnt.remote.stateDir)
if err != nil {
return "", err
}
if uid == 0 && gid == 0 {
return root, nil
}
p := string(filepath.Separator)
for _, d := range strings.Split(root, string(filepath.Separator))[1:] {
p = filepath.Join(p, d)
fi, err := os.Stat(p)
if err != nil && !os.IsNotExist(err) {
return "", err
}
if os.IsNotExist(err) || fi.Mode()&1 == 0 {
p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
if err := idtools.MkdirAs(p, 0700, uid, gid); err != nil && !os.IsExist(err) {
return "", err
}
}
}
return p, nil
}
func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) (err error) {
clnt.lock(containerID)
defer clnt.unlock(containerID)
if _, err := clnt.getContainer(containerID); err == nil {
return fmt.Errorf("Container %s is already active", containerID)
}
uid, gid, err := getRootIDs(specs.Spec(spec))
if err != nil {
return err
}
dir, err := clnt.prepareBundleDir(uid, gid)
if err != nil {
return err
}
container := clnt.newContainer(filepath.Join(dir, containerID), options...)
if err := container.clean(); err != nil {
return err
}
defer func() {
if err != nil {
container.clean()
clnt.deleteContainer(containerID)
}
}()
if err := idtools.MkdirAllAs(container.dir, 0700, uid, gid); err != nil && !os.IsExist(err) {
return err
}
f, err := os.Create(filepath.Join(container.dir, configFilename))
if err != nil {
return err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(spec); err != nil {
return err
}
return container.start(checkpoint, checkpointDir, attachStdio)
}
func (clnt *client) Signal(containerID string, sig int) error {
clnt.lock(containerID)
defer clnt.unlock(containerID)
_, err := clnt.remote.apiClient.Signal(context.Background(), &containerd.SignalRequest{
Id: containerID,
Pid: InitFriendlyName,
Signal: uint32(sig),
})
return err
}
func (clnt *client) SignalProcess(containerID string, pid string, sig int) error {
clnt.lock(containerID)
defer clnt.unlock(containerID)
@ -340,28 +256,6 @@ func (clnt *client) getContainerdContainer(containerID string) (*containerd.Cont
return nil, fmt.Errorf("invalid state response")
}
func (clnt *client) newContainer(dir string, options ...CreateOption) *container {
container := &container{
containerCommon: containerCommon{
process: process{
dir: dir,
processCommon: processCommon{
containerID: filepath.Base(dir),
client: clnt,
friendlyName: InitFriendlyName,
},
},
processes: make(map[string]*process),
},
}
for _, option := range options {
if err := option.Apply(container); err != nil {
logrus.Errorf("libcontainerd: newContainer(): %v", err)
}
}
return container
}
func (clnt *client) UpdateResources(containerID string, resources Resources) error {
clnt.lock(containerID)
defer clnt.unlock(containerID)
@ -627,27 +521,6 @@ func (clnt *client) Restore(containerID string, attachStdio StdioCallback, optio
return clnt.setExited(containerID, uint32(255))
}
type exitNotifier struct {
id string
client *client
c chan struct{}
once sync.Once
}
func (en *exitNotifier) close() {
en.once.Do(func() {
close(en.c)
en.client.mapMutex.Lock()
if en == en.client.exitNotifiers[en.id] {
delete(en.client.exitNotifiers, en.id)
}
en.client.mapMutex.Unlock()
})
}
func (en *exitNotifier) wait() <-chan struct{} {
return en.c
}
func (clnt *client) CreateCheckpoint(containerID string, checkpointID string, checkpointDir string, exit bool) error {
clnt.lock(containerID)
defer clnt.unlock(containerID)

View File

@ -6,17 +6,17 @@ type client struct {
clientCommon
// Platform specific properties below here.
remote *remote
q queue
exitNotifiers map[string]*exitNotifier
liveRestore bool
}
func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendlyName string, specp Process) error {
return nil
func (clnt *client) AddProcess(ctx context.Context, containerID, processFriendlyName string, specp Process, attachStdio StdioCallback) (int, error) {
return -1, nil
}
func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec Spec, options ...CreateOption) (err error) {
return nil
}
func (clnt *client) Signal(containerID string, sig int) error {
func (clnt *client) SignalProcess(containerID string, pid string, sig int) error {
return nil
}
@ -36,8 +36,25 @@ func (clnt *client) Stats(containerID string) (*Stats, error) {
return nil, nil
}
func (clnt *client) getExitNotifier(containerID string) *exitNotifier {
clnt.mapMutex.RLock()
defer clnt.mapMutex.RUnlock()
return clnt.exitNotifiers[containerID]
}
func (clnt *client) getOrCreateExitNotifier(containerID string) *exitNotifier {
clnt.mapMutex.Lock()
defer clnt.mapMutex.Unlock()
w, ok := clnt.exitNotifiers[containerID]
if !ok {
w = &exitNotifier{c: make(chan struct{}), client: clnt}
clnt.exitNotifiers[containerID] = w
}
return w
}
// Restore is the handler for restoring a container
func (clnt *client) Restore(containerID string, unusedOnWindows ...CreateOption) error {
func (clnt *client) Restore(containerID string, attachStdio StdioCallback, options ...CreateOption) error {
return nil
}
@ -56,3 +73,15 @@ func (clnt *client) UpdateResources(containerID string, resources Resources) err
// but we should return nil for enabling updating container
return nil
}
func (clnt *client) CreateCheckpoint(containerID string, checkpointID string, checkpointDir string, exit bool) error {
return nil
}
func (clnt *client) DeleteCheckpoint(containerID string, checkpointID string, checkpointDir string) error {
return nil
}
func (clnt *client) ListCheckpoints(containerID string, checkpointDir string) (*Checkpoints, error) {
return nil, nil
}

View File

@ -0,0 +1,142 @@
// +build linux solaris
package libcontainerd
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"sync"
"github.com/Sirupsen/logrus"
containerd "github.com/docker/containerd/api/grpc/types"
"github.com/docker/docker/pkg/idtools"
specs "github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/net/context"
)
func (clnt *client) prepareBundleDir(uid, gid int) (string, error) {
root, err := filepath.Abs(clnt.remote.stateDir)
if err != nil {
return "", err
}
if uid == 0 && gid == 0 {
return root, nil
}
p := string(filepath.Separator)
for _, d := range strings.Split(root, string(filepath.Separator))[1:] {
p = filepath.Join(p, d)
fi, err := os.Stat(p)
if err != nil && !os.IsNotExist(err) {
return "", err
}
if os.IsNotExist(err) || fi.Mode()&1 == 0 {
p = fmt.Sprintf("%s.%d.%d", p, uid, gid)
if err := idtools.MkdirAs(p, 0700, uid, gid); err != nil && !os.IsExist(err) {
return "", err
}
}
}
return p, nil
}
func (clnt *client) Create(containerID string, checkpoint string, checkpointDir string, spec specs.Spec, attachStdio StdioCallback, options ...CreateOption) (err error) {
clnt.lock(containerID)
defer clnt.unlock(containerID)
if _, err := clnt.getContainer(containerID); err == nil {
return fmt.Errorf("Container %s is already active", containerID)
}
uid, gid, err := getRootIDs(specs.Spec(spec))
if err != nil {
return err
}
dir, err := clnt.prepareBundleDir(uid, gid)
if err != nil {
return err
}
container := clnt.newContainer(filepath.Join(dir, containerID), options...)
if err := container.clean(); err != nil {
return err
}
defer func() {
if err != nil {
container.clean()
clnt.deleteContainer(containerID)
}
}()
if err := idtools.MkdirAllAs(container.dir, 0700, uid, gid); err != nil && !os.IsExist(err) {
return err
}
f, err := os.Create(filepath.Join(container.dir, configFilename))
if err != nil {
return err
}
defer f.Close()
if err := json.NewEncoder(f).Encode(spec); err != nil {
return err
}
return container.start(checkpoint, checkpointDir, attachStdio)
}
func (clnt *client) Signal(containerID string, sig int) error {
clnt.lock(containerID)
defer clnt.unlock(containerID)
_, err := clnt.remote.apiClient.Signal(context.Background(), &containerd.SignalRequest{
Id: containerID,
Pid: InitFriendlyName,
Signal: uint32(sig),
})
return err
}
func (clnt *client) newContainer(dir string, options ...CreateOption) *container {
container := &container{
containerCommon: containerCommon{
process: process{
dir: dir,
processCommon: processCommon{
containerID: filepath.Base(dir),
client: clnt,
friendlyName: InitFriendlyName,
},
},
processes: make(map[string]*process),
},
}
for _, option := range options {
if err := option.Apply(container); err != nil {
logrus.Errorf("libcontainerd: newContainer(): %v", err)
}
}
return container
}
type exitNotifier struct {
id string
client *client
c chan struct{}
once sync.Once
}
func (en *exitNotifier) close() {
en.once.Do(func() {
close(en.c)
en.client.mapMutex.Lock()
if en == en.client.exitNotifiers[en.id] {
delete(en.client.exitNotifiers, en.id)
}
en.client.mapMutex.Unlock()
})
}
func (en *exitNotifier) wait() <-chan struct{} {
return en.c
}

View File

@ -1,5 +0,0 @@
package libcontainerd
type container struct {
containerCommon
}

View File

@ -1,3 +1,5 @@
// +build linux solaris
package libcontainerd
import (

View File

@ -0,0 +1,31 @@
package libcontainerd
import (
"fmt"
"os"
"strconv"
"github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/system"
)
func setOOMScore(pid, score int) error {
oomScoreAdjPath := fmt.Sprintf("/proc/%d/oom_score_adj", pid)
f, err := os.OpenFile(oomScoreAdjPath, os.O_WRONLY, 0)
if err != nil {
return err
}
stringScore := strconv.Itoa(score)
_, err = f.WriteString(stringScore)
f.Close()
if os.IsPermission(err) {
// Setting oom_score_adj does not work in an
// unprivileged container. Ignore the error, but log
// it if we appear not to be in that situation.
if !system.RunningInUserNS() {
logrus.Debugf("Permission denied writing %q to %s", stringScore, oomScoreAdjPath)
}
return nil
}
return err
}

View File

@ -0,0 +1,5 @@
package libcontainerd
func setOOMScore(pid, score int) error {
return nil
}

View File

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

View File

@ -1,6 +0,0 @@
package libcontainerd
// process keeps the state for both main container process and exec process.
type process struct {
processCommon
}

View File

@ -1,3 +1,5 @@
// +build linux solaris
package libcontainerd
import (
@ -5,18 +7,19 @@ import (
"io/ioutil"
"os"
"path/filepath"
"syscall"
goruntime "runtime"
"time"
containerd "github.com/docker/containerd/api/grpc/types"
"github.com/tonistiigi/fifo"
"golang.org/x/net/context"
"golang.org/x/sys/unix"
)
var fdNames = map[int]string{
syscall.Stdin: "stdin",
syscall.Stdout: "stdout",
syscall.Stderr: "stderr",
unix.Stdin: "stdin",
unix.Stdout: "stdout",
unix.Stderr: "stderr",
}
// process keeps the state for both main container process and exec process.
@ -36,7 +39,7 @@ func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) {
io := &IOPipe{}
io.Stdin, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stdin), syscall.O_WRONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700)
io.Stdin, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdin), unix.O_WRONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
if err != nil {
return nil, err
}
@ -47,7 +50,7 @@ func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) {
}
}()
io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stdout), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700)
io.Stdout, err = fifo.OpenFifo(ctx, p.fifo(unix.Stdout), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
if err != nil {
return nil, err
}
@ -58,8 +61,10 @@ func (p *process) openFifos(terminal bool) (pipe *IOPipe, err error) {
}
}()
if !terminal {
io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(syscall.Stderr), syscall.O_RDONLY|syscall.O_CREAT|syscall.O_NONBLOCK, 0700)
if goruntime.GOOS == "solaris" || !terminal {
// For Solaris terminal handling is done exclusively by the runtime therefore we make no distinction
// in the processing for terminal and !terminal cases.
io.Stderr, err = fifo.OpenFifo(ctx, p.fifo(unix.Stderr), unix.O_RDONLY|unix.O_CREAT|unix.O_NONBLOCK, 0700)
if err != nil {
return nil, err
}

View File

@ -1,3 +1,5 @@
// +build linux solaris
package libcontainerd
import "sync"

View File

@ -1,34 +0,0 @@
package libcontainerd
import "github.com/docker/docker/pkg/locker"
type remote struct {
}
func (r *remote) Client(b Backend) (Client, error) {
c := &client{
clientCommon: clientCommon{
backend: b,
containers: make(map[string]*container),
locker: locker.New(),
},
}
return c, nil
}
func (r *remote) Cleanup() {
}
func (r *remote) UpdateOptions(opts ...RemoteOption) error {
return nil
}
// New creates a fresh instance of libcontainerd remote.
func New(_ string, _ ...RemoteOption) (Remote, error) {
return &remote{}, nil
}
// WithLiveRestore is a noop on solaris.
func WithLiveRestore(v bool) RemoteOption {
return nil
}

View File

@ -1,3 +1,5 @@
// +build linux solaris
package libcontainerd
import (
@ -9,6 +11,7 @@ import (
"os"
"os/exec"
"path/filepath"
goruntime "runtime"
"strconv"
"strings"
"sync"
@ -22,7 +25,6 @@ import (
"github.com/docker/docker/utils"
"github.com/golang/protobuf/ptypes"
"github.com/golang/protobuf/ptypes/timestamp"
rsystem "github.com/opencontainers/runc/libcontainer/system"
"golang.org/x/net/context"
"google.golang.org/grpc"
"google.golang.org/grpc/grpclog"
@ -374,14 +376,18 @@ func (r *remote) runContainerdDaemon() error {
// Start a new instance
args := []string{
"-l", fmt.Sprintf("unix://%s", r.rpcAddr),
"--shim", "docker-containerd-shim",
"--metrics-interval=0",
"--start-timeout", "2m",
"--state-dir", filepath.Join(r.stateDir, containerdStateDir),
}
if r.runtime != "" {
args = append(args, "--runtime")
args = append(args, r.runtime)
if goruntime.GOOS == "solaris" {
args = append(args, "--shim", "containerd-shim", "--runtime", "runc")
} else {
args = append(args, "--shim", "docker-containerd-shim")
if r.runtime != "" {
args = append(args, "--runtime")
args = append(args, r.runtime)
}
}
if r.debugLog {
args = append(args, "--debug")
@ -398,7 +404,7 @@ func (r *remote) runContainerdDaemon() error {
// redirect containerd logs to docker logs
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true, Pdeathsig: syscall.SIGKILL}
cmd.SysProcAttr = setSysProcAttr(true)
cmd.Env = nil
// clear the NOTIFY_SOCKET from the env when starting containerd
for _, e := range os.Environ() {
@ -428,27 +434,6 @@ func (r *remote) runContainerdDaemon() error {
return nil
}
func setOOMScore(pid, score int) error {
oomScoreAdjPath := fmt.Sprintf("/proc/%d/oom_score_adj", pid)
f, err := os.OpenFile(oomScoreAdjPath, os.O_WRONLY, 0)
if err != nil {
return err
}
stringScore := strconv.Itoa(score)
_, err = f.WriteString(stringScore)
f.Close()
if os.IsPermission(err) {
// Setting oom_score_adj does not work in an
// unprivileged container. Ignore the error, but log
// it if we appear not to be in that situation.
if !rsystem.RunningInUserNS() {
logrus.Debugf("Permission denied writing %q to %s", stringScore, oomScoreAdjPath)
}
return nil
}
return err
}
// WithRemoteAddr sets the external containerd socket to connect to.
func WithRemoteAddr(addr string) RemoteOption {
return rpcAddr(addr)

View File

@ -1,11 +1,25 @@
package libcontainerd
import (
containerd "github.com/docker/containerd/api/grpc/types"
"github.com/opencontainers/runtime-spec/specs-go"
)
// Process contains information to start a specific application inside the container.
type Process struct {
// Terminal creates an interactive terminal for the container.
Terminal bool `json:"terminal"`
// User specifies user information for the process.
User *specs.User `json:"user"`
// Args specifies the binary and arguments for the application to execute.
Args []string `json:"args"`
// Env populates the process environment for the process.
Env []string `json:"env,omitempty"`
// Cwd is the current working directory for the process and must be
// relative to the container's root.
Cwd *string `json:"cwd"`
// Capabilities are linux capabilities that are kept for the container.
Capabilities []string `json:"capabilities,omitempty"`
}
// Stats contains a stats properties from containerd.
@ -19,7 +33,11 @@ type StateInfo struct {
CommonStateInfo
// Platform specific StateInfo
OOMKilled bool
}
// Resources defines updatable container resource values.
type Resources struct{}
// Checkpoints contains the details of a checkpoint
type Checkpoints containerd.ListCheckpointResponse

View File

@ -1,6 +1,8 @@
package libcontainerd
import (
"syscall"
containerd "github.com/docker/containerd/api/grpc/types"
"github.com/opencontainers/runtime-spec/specs-go"
)
@ -50,3 +52,11 @@ func convertRlimits(sr []specs.Rlimit) (cr []*containerd.Rlimit) {
}
return
}
// setPDeathSig sets the parent death signal to SIGKILL
func setSysProcAttr(sid bool) *syscall.SysProcAttr {
return &syscall.SysProcAttr{
Setsid: sid,
Pdeathsig: syscall.SIGKILL,
}
}

View File

@ -0,0 +1,27 @@
package libcontainerd
import (
"syscall"
containerd "github.com/docker/containerd/api/grpc/types"
"github.com/opencontainers/runtime-spec/specs-go"
)
func getRootIDs(s specs.Spec) (int, int, error) {
return 0, 0, nil
}
func systemPid(ctr *containerd.Container) uint32 {
var pid uint32
for _, p := range ctr.Processes {
if p.Pid == InitFriendlyName {
pid = p.SystemPid
}
}
return pid
}
// setPDeathSig sets the parent death signal to SIGKILL
func setSysProcAttr(sid bool) *syscall.SysProcAttr {
return nil
}

View File

@ -1,11 +1,20 @@
package oci
import (
"runtime"
"github.com/opencontainers/runtime-spec/specs-go"
)
// DefaultSpec returns default oci spec used by docker.
func DefaultSpec() specs.Spec {
s := specs.Spec{}
s := specs.Spec{
Version: "0.6.0",
Platform: specs.Platform{
OS: "SunOS",
Arch: runtime.GOARCH,
},
}
s.Solaris = &specs.Solaris{}
return s
}

View File

@ -67,7 +67,7 @@ func TestIsArchivePathDir(t *testing.T) {
}
func TestIsArchivePathInvalidFile(t *testing.T) {
cmd := exec.Command("sh", "-c", "dd if=/dev/zero bs=1K count=1 of=/tmp/archive && gzip --stdout /tmp/archive > /tmp/archive.gz")
cmd := exec.Command("sh", "-c", "dd if=/dev/zero bs=1024 count=1 of=/tmp/archive && gzip --stdout /tmp/archive > /tmp/archive.gz")
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Fail to create an archive file for test : %s.", output)
@ -81,7 +81,14 @@ func TestIsArchivePathInvalidFile(t *testing.T) {
}
func TestIsArchivePathTar(t *testing.T) {
cmd := exec.Command("sh", "-c", "touch /tmp/archivedata && tar -cf /tmp/archive /tmp/archivedata && gzip --stdout /tmp/archive > /tmp/archive.gz")
var whichTar string
if runtime.GOOS == "solaris" {
whichTar = "gtar"
} else {
whichTar = "tar"
}
cmdStr := fmt.Sprintf("touch /tmp/archivedata && %s -cf /tmp/archive /tmp/archivedata && gzip --stdout /tmp/archive > /tmp/archive.gz", whichTar)
cmd := exec.Command("sh", "-c", cmdStr)
output, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("Fail to create an archive file for test : %s.", output)

View File

@ -8,6 +8,7 @@ import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"syscall"
"testing"
@ -203,6 +204,9 @@ func TestTarWithBlockCharFifo(t *testing.T) {
// TestTarUntarWithXattr is Unix as Lsetxattr is not supported on Windows
func TestTarUntarWithXattr(t *testing.T) {
if runtime.GOOS == "solaris" {
t.Skip()
}
origin, err := ioutil.TempDir("", "docker-test-untar-origin")
if err != nil {
t.Fatal(err)

View File

@ -7,11 +7,16 @@ import (
"io/ioutil"
"os"
"path"
"runtime"
"sort"
"testing"
)
func TestHardLinkOrder(t *testing.T) {
//TODO Should run for Solaris
if runtime.GOOS == "solaris" {
t.Skip("gcp failures on Solaris")
}
names := []string{"file1.txt", "file2.txt", "file3.txt"}
msg := []byte("Hey y'all")

View File

@ -22,6 +22,10 @@ func max(x, y int) int {
func copyDir(src, dst string) error {
cmd := exec.Command("cp", "-a", src, dst)
if runtime.GOOS == "solaris" {
cmd = exec.Command("gcp", "-a", src, dst)
}
if err := cmd.Run(); err != nil {
return err
}
@ -256,8 +260,9 @@ func TestChangesWithChangesGH13590(t *testing.T) {
func TestChangesDirsEmpty(t *testing.T) {
// TODO Windows. There may be a way of running this, but turning off for now
// as createSampleDir uses symlinks.
if runtime.GOOS == "windows" {
t.Skip("symlinks on Windows")
// TODO Should work for Solaris
if runtime.GOOS == "windows" || runtime.GOOS == "solaris" {
t.Skip("symlinks on Windows; gcp failure on Solaris")
}
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {
@ -364,8 +369,9 @@ func mutateSampleDir(t *testing.T, root string) {
func TestChangesDirsMutated(t *testing.T) {
// TODO Windows. There may be a way of running this, but turning off for now
// as createSampleDir uses symlinks.
if runtime.GOOS == "windows" {
t.Skip("symlinks on Windows")
// TODO Should work for Solaris
if runtime.GOOS == "windows" || runtime.GOOS == "solaris" {
t.Skip("symlinks on Windows; gcp failures on Solaris")
}
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {
@ -425,8 +431,9 @@ func TestChangesDirsMutated(t *testing.T) {
func TestApplyLayer(t *testing.T) {
// TODO Windows. There may be a way of running this, but turning off for now
// as createSampleDir uses symlinks.
if runtime.GOOS == "windows" {
t.Skip("symlinks on Windows")
// TODO Should work for Solaris
if runtime.GOOS == "windows" || runtime.GOOS == "solaris" {
t.Skip("symlinks on Windows; gcp failures on Solaris")
}
src, err := ioutil.TempDir("", "docker-changes-test")
if err != nil {

View File

@ -165,7 +165,7 @@ func TestChrootTarUntarWithSymlink(t *testing.T) {
if err := system.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if _, err := prepareSourceDirectory(10, src, true); err != nil {
if _, err := prepareSourceDirectory(10, src, false); err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "dest")
@ -179,8 +179,8 @@ func TestChrootTarUntarWithSymlink(t *testing.T) {
func TestChrootCopyWithTar(t *testing.T) {
// TODO Windows: Figure out why this is failing
if runtime.GOOS == "windows" {
t.Skip("Failing on Windows")
if runtime.GOOS == "windows" || runtime.GOOS == "solaris" {
t.Skip("Failing on Windows and Solaris")
}
tmpdir, err := ioutil.TempDir("", "docker-TestChrootCopyWithTar")
if err != nil {
@ -284,7 +284,7 @@ func TestChrootUntarPath(t *testing.T) {
if err := system.MkdirAll(src, 0700); err != nil {
t.Fatal(err)
}
if _, err := prepareSourceDirectory(10, src, true); err != nil {
if _, err := prepareSourceDirectory(10, src, false); err != nil {
t.Fatal(err)
}
dest := filepath.Join(tmpdir, "dest")

View File

@ -15,14 +15,20 @@ func TestRunCommand(t *testing.T) {
t.Skip("Needs porting to Windows")
}
result := RunCommand("ls")
var cmd string
if runtime.GOOS == "solaris" {
cmd = "gls"
} else {
cmd = "ls"
}
result := RunCommand(cmd)
result.Assert(t, Expected{})
result = RunCommand("doesnotexists")
expectedError := `exec: "doesnotexists": executable file not found`
result.Assert(t, Expected{ExitCode: 127, Error: expectedError})
result = RunCommand("ls", "-z")
result = RunCommand(cmd, "-z")
result.Assert(t, Expected{
ExitCode: 2,
Error: "exit status 2",
@ -90,11 +96,19 @@ func TestRunCommandWithStdoutStderrError(t *testing.T) {
switch runtime.GOOS {
case "windows":
expected = "ls: unknown option"
case "solaris":
expected = "gls: invalid option"
default:
expected = "ls: invalid option"
}
result = RunCommand("ls", "-z")
var cmd string
if runtime.GOOS == "solaris" {
cmd = "gls"
} else {
cmd = "ls"
}
result = RunCommand(cmd, "-z")
result.Assert(t, Expected{
Out: None,
Err: expected,

View File

@ -83,6 +83,10 @@ func TestRunCommandPipelineWithOutputErrors(t *testing.T) {
}
func TestRunCommandPipelineWithOutput(t *testing.T) {
//TODO: Should run on Solaris
if runtime.GOOS == "solaris" {
t.Skip()
}
cmds := []*exec.Cmd{
// Print 2 characters
exec.Command("echo", "-n", "11"),

View File

@ -1,4 +1,4 @@
// +build !windows
// +build !windows,!solaris
package mount

View File

@ -0,0 +1,58 @@
// +build solaris
package mount
// MakeShared ensures a mounted filesystem has the SHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeShared(mountPoint string) error {
return ensureMountedAs(mountPoint, "shared")
}
// MakeRShared ensures a mounted filesystem has the RSHARED mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRShared(mountPoint string) error {
return ensureMountedAs(mountPoint, "rshared")
}
// MakePrivate ensures a mounted filesystem has the PRIVATE mount option enabled.
// See the supported options in flags.go for further reference.
func MakePrivate(mountPoint string) error {
return ensureMountedAs(mountPoint, "private")
}
// MakeRPrivate ensures a mounted filesystem has the RPRIVATE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeRPrivate(mountPoint string) error {
return ensureMountedAs(mountPoint, "rprivate")
}
// MakeSlave ensures a mounted filesystem has the SLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeSlave(mountPoint string) error {
return ensureMountedAs(mountPoint, "slave")
}
// MakeRSlave ensures a mounted filesystem has the RSLAVE mount option enabled.
// See the supported options in flags.go for further reference.
func MakeRSlave(mountPoint string) error {
return ensureMountedAs(mountPoint, "rslave")
}
// MakeUnbindable ensures a mounted filesystem has the UNBINDABLE mount option
// enabled. See the supported options in flags.go for further reference.
func MakeUnbindable(mountPoint string) error {
return ensureMountedAs(mountPoint, "unbindable")
}
// MakeRUnbindable ensures a mounted filesystem has the RUNBINDABLE mount
// option enabled. See the supported options in flags.go for further reference.
func MakeRUnbindable(mountPoint string) error {
return ensureMountedAs(mountPoint, "runbindable")
}
func ensureMountedAs(mountPoint, options string) error {
// TODO: Solaris does not support bind mounts.
// Evaluate lofs and also look at the relevant
// mount flags to be supported.
return nil
}

28
plugin/manager_solaris.go Normal file
View File

@ -0,0 +1,28 @@
package plugin
import (
"fmt"
"github.com/docker/docker/plugin/v2"
specs "github.com/opencontainers/runtime-spec/specs-go"
)
func (pm *Manager) enable(p *v2.Plugin, force bool) error {
return fmt.Errorf("Not implemented")
}
func (pm *Manager) initSpec(p *v2.Plugin) (*specs.Spec, error) {
return nil, fmt.Errorf("Not implemented")
}
func (pm *Manager) disable(p *v2.Plugin) error {
return fmt.Errorf("Not implemented")
}
func (pm *Manager) restore(p *v2.Plugin) error {
return fmt.Errorf("Not implemented")
}
// Shutdown plugins
func (pm *Manager) Shutdown() {
}

View File

@ -1,3 +1,7 @@
// +build !solaris
// TODO: Support Solaris
package registry
import (

View File

@ -1,3 +1,5 @@
// +build !solaris
package registry
import (

View File

@ -1,3 +1,5 @@
// +build !solaris
package registry
import (

View File

@ -26,6 +26,11 @@ func TestDecodeContainerConfig(t *testing.T) {
image string
)
//TODO: Should run for Solaris
if runtime.GOOS == "solaris" {
t.Skip()
}
if runtime.GOOS != "windows" {
image = "ubuntu"
fixtures = []f{

View File

@ -1,9 +1,6 @@
package runconfig
import (
"fmt"
"strings"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/pkg/sysinfo"
)
@ -11,7 +8,7 @@ import (
// DefaultDaemonNetworkMode returns the default network stack the daemon should
// use.
func DefaultDaemonNetworkMode() container.NetworkMode {
return container.NetworkMode("default")
return container.NetworkMode("bridge")
}
// IsPreDefinedNetwork indicates if a network is predefined by the daemon
@ -23,15 +20,6 @@ func IsPreDefinedNetwork(network string) bool {
// network settings are valid.
func ValidateNetMode(c *container.Config, hc *container.HostConfig) error {
// We may not be passed a host config, such as in the case of docker commit
if hc == nil {
return nil
}
parts := strings.Split(string(hc.NetworkMode), ":")
switch mode := parts[0]; mode {
case "default", "none":
default:
return fmt.Errorf("invalid --net: %s", hc.NetworkMode)
}
return nil
}

View File

@ -1,4 +1,4 @@
// +build linux freebsd
// +build linux freebsd solaris
package utils

View File

@ -164,10 +164,9 @@ func TestValidateName(t *testing.T) {
}
func TestCreateWithOpts(t *testing.T) {
if runtime.GOOS == "windows" {
if runtime.GOOS == "windows" || runtime.GOOS == "solaris" {
t.Skip()
}
rootDir, err := ioutil.TempDir("", "local-volume-test")
if err != nil {
t.Fatal(err)