Selaa lähdekoodia

Merge pull request #28056 from LK4D4/solaris_me

Add functional support for Docker sub commands on Solaris
Tibor Vass 8 vuotta sitten
vanhempi
commit
109c26bd74
77 muutettua tiedostoa jossa 1572 lisäystä ja 571 poistoa
  1. 2 1
      Dockerfile
  2. 20 0
      Dockerfile.solaris
  3. 5 0
      cmd/dockerd/daemon_solaris.go
  4. 5 3
      cmd/dockerd/daemon_unix_test.go
  5. 9 0
      container/container_linux.go
  6. 13 0
      container/container_notlinux.go
  7. 0 100
      container/container_solaris.go
  8. 3 7
      container/container_unix.go
  9. 5 2
      container/memory_store.go
  10. 1 1
      contrib/docker-device-tool/device_tool.go
  11. 4 0
      contrib/httpserver/Dockerfile.solaris
  12. 11 0
      contrib/mkimage.sh
  13. 89 0
      contrib/mkimage/solaris
  14. 5 0
      daemon/bindmount_solaris.go
  15. 5 0
      daemon/bindmount_unix.go
  16. 1 1
      daemon/cluster/listen_addr_others.go
  17. 57 0
      daemon/cluster/listen_addr_solaris.go
  18. 3 3
      daemon/commit.go
  19. 4 0
      daemon/config.go
  20. 80 0
      daemon/config_common_unix.go
  21. 9 7
      daemon/config_solaris.go
  22. 4 0
      daemon/config_test.go
  23. 16 63
      daemon/config_unix.go
  24. 18 10
      daemon/container_operations_solaris.go
  25. 0 83
      daemon/container_operations_unix.go
  26. 11 4
      daemon/create.go
  27. 360 10
      daemon/daemon_solaris.go
  28. 2 0
      daemon/daemon_test.go
  29. 1 1
      daemon/daemon_unix_test.go
  30. 41 0
      daemon/getsize_unix.go
  31. 32 0
      daemon/graphdriver/driver_solaris.go
  32. 1 1
      daemon/graphdriver/graphtest/graphtest_unix.go
  33. 3 2
      daemon/inspect_solaris.go
  34. 11 3
      daemon/network.go
  35. 169 0
      daemon/oci_solaris.go
  36. 3 3
      daemon/start.go
  37. 2 0
      daemon/start_unix.go
  38. 4 0
      daemon/stats.go
  39. 51 0
      daemon/volumes_unix.go
  40. 3 0
      hack/make/.detect-daemon-osarch
  41. 12 9
      hack/make/cross
  42. 24 9
      hack/make/test-unit
  43. 3 0
      hack/make/tgz
  44. 0 127
      libcontainerd/client_linux.go
  45. 37 8
      libcontainerd/client_solaris.go
  46. 142 0
      libcontainerd/client_unix.go
  47. 0 5
      libcontainerd/container_solaris.go
  48. 2 0
      libcontainerd/container_unix.go
  49. 31 0
      libcontainerd/oom_linux.go
  50. 5 0
      libcontainerd/oom_solaris.go
  51. 2 0
      libcontainerd/pausemonitor_unix.go
  52. 0 6
      libcontainerd/process_solaris.go
  53. 13 8
      libcontainerd/process_unix.go
  54. 2 0
      libcontainerd/queue_unix.go
  55. 0 34
      libcontainerd/remote_solaris.go
  56. 12 27
      libcontainerd/remote_unix.go
  57. 18 0
      libcontainerd/types_solaris.go
  58. 10 0
      libcontainerd/utils_linux.go
  59. 27 0
      libcontainerd/utils_solaris.go
  60. 10 1
      oci/defaults_solaris.go
  61. 9 2
      pkg/archive/archive_test.go
  62. 4 0
      pkg/archive/archive_unix_test.go
  63. 5 0
      pkg/archive/changes_posix_test.go
  64. 13 6
      pkg/archive/changes_test.go
  65. 4 4
      pkg/chrootarchive/archive_test.go
  66. 17 3
      pkg/integration/cmd/command_test.go
  67. 4 0
      pkg/integration/utils_test.go
  68. 1 1
      pkg/mount/mount_unix_test.go
  69. 58 0
      pkg/mount/sharedsubtree_solaris.go
  70. 28 0
      plugin/manager_solaris.go
  71. 4 0
      registry/auth_test.go
  72. 2 0
      registry/registry_mock_test.go
  73. 2 0
      registry/registry_test.go
  74. 5 0
      runconfig/config_test.go
  75. 1 13
      runconfig/hostconfig_solaris.go
  76. 1 1
      utils/process_unix.go
  77. 1 2
      volume/local/local_test.go

+ 2 - 1
Dockerfile

@@ -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 - 0
Dockerfile.solaris

@@ -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

+ 5 - 0
cmd/dockerd/daemon_solaris.go

@@ -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
 }
 

+ 5 - 3
cmd/dockerd/daemon_unix_test.go

@@ -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 - 0
container/container_linux.go

@@ -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 - 0
container/container_notlinux.go

@@ -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)
+}

+ 0 - 100
container/container_solaris.go

@@ -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
-}

+ 3 - 7
container/container_unix.go

@@ -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 (

+ 5 - 2
container/memory_store.go

@@ -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 - 1
contrib/docker-device-tool/device_tool.go

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

+ 4 - 0
contrib/httpserver/Dockerfile.solaris

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

+ 11 - 0
contrib/mkimage.sh

@@ -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 - 0
contrib/mkimage/solaris

@@ -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 - 0
daemon/bindmount_solaris.go

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

+ 5 - 0
daemon/bindmount_unix.go

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

+ 1 - 1
daemon/cluster/listen_addr_others.go

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

+ 57 - 0
daemon/cluster/listen_addr_solaris.go

@@ -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
+}

+ 3 - 3
daemon/commit.go

@@ -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() {

+ 4 - 0
daemon/config.go

@@ -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 - 0
daemon/config_common_unix.go

@@ -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
+}

+ 9 - 7
daemon/config_solaris.go

@@ -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
 }

+ 4 - 0
daemon/config_test.go

@@ -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)

+ 16 - 63
daemon/config_unix.go

@@ -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")

+ 18 - 10
daemon/container_operations_solaris.go

@@ -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) {
+}

+ 0 - 83
daemon/container_operations_unix.go

@@ -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

+ 11 - 4
daemon/create.go

@@ -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)
 }

+ 360 - 10
daemon/daemon_solaris.go

@@ -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
 }

+ 2 - 0
daemon/daemon_test.go

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

+ 1 - 1
daemon/daemon_unix_test.go

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

+ 41 - 0
daemon/getsize_unix.go

@@ -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
+}

+ 32 - 0
daemon/graphdriver/driver_solaris.go

@@ -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 - 1
daemon/graphdriver/graphtest/graphtest_unix.go

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

+ 3 - 2
daemon/inspect_solaris.go

@@ -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 {

+ 11 - 3
daemon/network.go

@@ -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 {

+ 169 - 0
daemon/oci_solaris.go

@@ -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
 }
 

+ 3 - 3
daemon/start.go

@@ -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.

+ 2 - 0
daemon/start_linux.go → daemon/start_unix.go

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

+ 4 - 0
daemon/stats.go

@@ -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
 

+ 51 - 0
daemon/volumes_unix.go

@@ -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
+}

+ 3 - 0
hack/make/.detect-daemon-osarch

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

+ 12 - 9
hack/make/cross

@@ -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

+ 24 - 9
hack/make/test-unit

@@ -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
 }
 

+ 3 - 0
hack/make/tgz

@@ -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"

+ 0 - 127
libcontainerd/client_linux.go

@@ -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)

+ 37 - 8
libcontainerd/client_solaris.go

@@ -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 - 0
libcontainerd/client_unix.go

@@ -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
+}

+ 0 - 5
libcontainerd/container_solaris.go

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

+ 2 - 0
libcontainerd/container_linux.go → libcontainerd/container_unix.go

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

+ 31 - 0
libcontainerd/oom_linux.go

@@ -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 - 0
libcontainerd/oom_solaris.go

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

+ 2 - 0
libcontainerd/pausemonitor_linux.go → libcontainerd/pausemonitor_unix.go

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

+ 0 - 6
libcontainerd/process_solaris.go

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

+ 13 - 8
libcontainerd/process_linux.go → libcontainerd/process_unix.go

@@ -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
 		}

+ 2 - 0
libcontainerd/queue_linux.go → libcontainerd/queue_unix.go

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

+ 0 - 34
libcontainerd/remote_solaris.go

@@ -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
-}

+ 12 - 27
libcontainerd/remote_linux.go → libcontainerd/remote_unix.go

@@ -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)

+ 18 - 0
libcontainerd/types_solaris.go

@@ -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

+ 10 - 0
libcontainerd/utils_linux.go

@@ -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 - 0
libcontainerd/utils_solaris.go

@@ -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
+}

+ 10 - 1
oci/defaults_solaris.go

@@ -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
 }

+ 9 - 2
pkg/archive/archive_test.go

@@ -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)

+ 4 - 0
pkg/archive/archive_unix_test.go

@@ -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)

+ 5 - 0
pkg/archive/changes_posix_test.go

@@ -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")
 

+ 13 - 6
pkg/archive/changes_test.go

@@ -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 {

+ 4 - 4
pkg/chrootarchive/archive_test.go

@@ -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")

+ 17 - 3
pkg/integration/cmd/command_test.go

@@ -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,

+ 4 - 0
pkg/integration/utils_test.go

@@ -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 - 1
pkg/mount/mount_unix_test.go

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

+ 58 - 0
pkg/mount/sharedsubtree_solaris.go

@@ -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 - 0
plugin/manager_solaris.go

@@ -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() {
+}

+ 4 - 0
registry/auth_test.go

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

+ 2 - 0
registry/registry_mock_test.go

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

+ 2 - 0
registry/registry_test.go

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

+ 5 - 0
runconfig/config_test.go

@@ -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 - 13
runconfig/hostconfig_solaris.go

@@ -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 - 1
utils/process_unix.go

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

+ 1 - 2
volume/local/local_test.go

@@ -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)