mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #28056 from LK4D4/solaris_me
Add functional support for Docker sub commands on Solaris
This commit is contained in:
commit
109c26bd74
77 changed files with 1572 additions and 571 deletions
|
@ -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
20
Dockerfile.solaris
Normal 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
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
9
container/container_linux.go
Normal file
9
container/container_linux.go
Normal 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)
|
||||
}
|
13
container/container_notlinux.go
Normal file
13
container/container_notlinux.go
Normal 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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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 (
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows
|
||||
// +build !windows,!solaris
|
||||
|
||||
package main
|
||||
|
||||
|
|
4
contrib/httpserver/Dockerfile.solaris
Normal file
4
contrib/httpserver/Dockerfile.solaris
Normal file
|
@ -0,0 +1,4 @@
|
|||
FROM solaris
|
||||
EXPOSE 80/tcp
|
||||
COPY httpserver .
|
||||
CMD ["./httpserver"]
|
|
@ -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
89
contrib/mkimage/solaris
Executable 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"
|
5
daemon/bindmount_solaris.go
Normal file
5
daemon/bindmount_solaris.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
// +build solaris
|
||||
|
||||
package daemon
|
||||
|
||||
const bindMountType = "lofs"
|
5
daemon/bindmount_unix.go
Normal file
5
daemon/bindmount_unix.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package daemon
|
||||
|
||||
const bindMountType = "bind"
|
|
@ -1,4 +1,4 @@
|
|||
// +build !linux
|
||||
// +build !linux,!solaris
|
||||
|
||||
package cluster
|
||||
|
||||
|
|
57
daemon/cluster/listen_addr_solaris.go
Normal file
57
daemon/cluster/listen_addr_solaris.go
Normal 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
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
80
daemon/config_common_unix.go
Normal file
80
daemon/config_common_unix.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !solaris
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows
|
||||
// +build !windows,!solaris
|
||||
|
||||
package daemon
|
||||
|
||||
|
|
41
daemon/getsize_unix.go
Normal file
41
daemon/getsize_unix.go
Normal 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
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build linux freebsd
|
||||
// +build linux freebsd solaris
|
||||
|
||||
package graphtest
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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"
|
||||
)
|
||||
|
||||
|
@ -240,7 +242,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
|
||||
|
@ -340,6 +342,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
|
||||
|
@ -350,6 +355,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 {
|
||||
|
@ -405,7 +413,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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !windows
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -56,6 +56,9 @@ case "$PACKAGE_ARCH" in
|
|||
windows)
|
||||
DOCKERFILE='Dockerfile.windows'
|
||||
;;
|
||||
solaris)
|
||||
DOCKERFILE='Dockerfile.solaris'
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
142
libcontainerd/client_unix.go
Normal file
142
libcontainerd/client_unix.go
Normal 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
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package libcontainerd
|
||||
|
||||
type container struct {
|
||||
containerCommon
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux solaris
|
||||
|
||||
package libcontainerd
|
||||
|
||||
import (
|
31
libcontainerd/oom_linux.go
Normal file
31
libcontainerd/oom_linux.go
Normal 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
|
||||
}
|
5
libcontainerd/oom_solaris.go
Normal file
5
libcontainerd/oom_solaris.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package libcontainerd
|
||||
|
||||
func setOOMScore(pid, score int) error {
|
||||
return nil
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// +build !windows
|
||||
|
||||
package libcontainerd
|
||||
|
||||
import (
|
|
@ -1,6 +0,0 @@
|
|||
package libcontainerd
|
||||
|
||||
// process keeps the state for both main container process and exec process.
|
||||
type process struct {
|
||||
processCommon
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,3 +1,5 @@
|
|||
// +build linux solaris
|
||||
|
||||
package libcontainerd
|
||||
|
||||
import "sync"
|
|
@ -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
|
||||
}
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
27
libcontainerd/utils_solaris.go
Normal file
27
libcontainerd/utils_solaris.go
Normal 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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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"),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build !windows
|
||||
// +build !windows,!solaris
|
||||
|
||||
package mount
|
||||
|
||||
|
|
58
pkg/mount/sharedsubtree_solaris.go
Normal file
58
pkg/mount/sharedsubtree_solaris.go
Normal 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
28
plugin/manager_solaris.go
Normal 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() {
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
// +build !solaris
|
||||
|
||||
// TODO: Support Solaris
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !solaris
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
// +build !solaris
|
||||
|
||||
package registry
|
||||
|
||||
import (
|
||||
|
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// +build linux freebsd
|
||||
// +build linux freebsd solaris
|
||||
|
||||
package utils
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue