2015-05-15 19:34:26 -04:00
|
|
|
package daemon
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2016-01-07 22:43:11 -05:00
|
|
|
"os"
|
2017-02-02 14:22:12 -05:00
|
|
|
"path/filepath"
|
2015-11-18 17:20:54 -05:00
|
|
|
"strings"
|
2017-02-01 13:52:16 -05:00
|
|
|
"syscall"
|
|
|
|
"unsafe"
|
2015-05-15 19:34:26 -04:00
|
|
|
|
2016-03-09 23:33:21 -05:00
|
|
|
"github.com/Microsoft/hcsshim"
|
2015-09-22 19:05:00 -04:00
|
|
|
"github.com/Sirupsen/logrus"
|
2016-09-06 14:18:12 -04:00
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
containertypes "github.com/docker/docker/api/types/container"
|
2015-11-12 14:55:17 -05:00
|
|
|
"github.com/docker/docker/container"
|
2017-01-23 06:23:07 -05:00
|
|
|
"github.com/docker/docker/daemon/config"
|
2015-11-18 17:20:54 -05:00
|
|
|
"github.com/docker/docker/image"
|
2016-01-07 22:43:11 -05:00
|
|
|
"github.com/docker/docker/pkg/idtools"
|
2016-03-18 14:53:27 -04:00
|
|
|
"github.com/docker/docker/pkg/parsers"
|
2016-09-07 19:08:51 -04:00
|
|
|
"github.com/docker/docker/pkg/platform"
|
2016-02-24 20:51:46 -05:00
|
|
|
"github.com/docker/docker/pkg/sysinfo"
|
2015-10-15 14:40:14 -04:00
|
|
|
"github.com/docker/docker/pkg/system"
|
2016-02-24 20:51:46 -05:00
|
|
|
"github.com/docker/docker/runconfig"
|
2015-05-15 19:34:26 -04:00
|
|
|
"github.com/docker/libnetwork"
|
2016-02-17 20:08:11 -05:00
|
|
|
nwconfig "github.com/docker/libnetwork/config"
|
2016-11-09 20:54:15 -05:00
|
|
|
"github.com/docker/libnetwork/datastore"
|
2016-03-09 23:33:21 -05:00
|
|
|
winlibnetwork "github.com/docker/libnetwork/drivers/windows"
|
|
|
|
"github.com/docker/libnetwork/netlabel"
|
|
|
|
"github.com/docker/libnetwork/options"
|
2015-06-11 20:34:20 -04:00
|
|
|
blkiodev "github.com/opencontainers/runc/libcontainer/configs"
|
2016-11-18 15:34:25 -05:00
|
|
|
"golang.org/x/sys/windows"
|
2015-05-15 19:34:26 -04:00
|
|
|
)
|
|
|
|
|
2015-08-07 12:33:29 -04:00
|
|
|
const (
|
2016-11-01 16:02:46 -04:00
|
|
|
defaultNetworkSpace = "172.16.0.0/12"
|
|
|
|
platformSupported = true
|
|
|
|
windowsMinCPUShares = 1
|
|
|
|
windowsMaxCPUShares = 10000
|
|
|
|
windowsMinCPUPercent = 1
|
|
|
|
windowsMaxCPUPercent = 100
|
|
|
|
windowsMinCPUCount = 1
|
2017-02-01 13:52:16 -05:00
|
|
|
|
|
|
|
errInvalidState = syscall.Errno(0x139F)
|
2015-08-07 12:33:29 -04:00
|
|
|
)
|
2015-07-13 15:34:58 -04:00
|
|
|
|
2017-02-02 14:22:12 -05:00
|
|
|
// Windows has no concept of an execution state directory. So use config.Root here.
|
|
|
|
func getPluginExecRoot(root string) string {
|
|
|
|
return filepath.Join(root, "plugins")
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:53:27 -04:00
|
|
|
func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
|
2015-06-11 20:34:20 -04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2017-01-08 20:22:05 -05:00
|
|
|
func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
|
|
|
return parseSecurityOpt(container, hostConfig)
|
|
|
|
}
|
|
|
|
|
2015-12-18 13:36:17 -05:00
|
|
|
func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
|
2015-05-15 19:34:26 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:53:27 -04:00
|
|
|
func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
2015-07-08 07:06:48 -04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:53:27 -04:00
|
|
|
func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
2015-07-08 07:06:48 -04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:53:27 -04:00
|
|
|
func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
2015-07-08 07:06:48 -04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2016-03-18 14:53:27 -04:00
|
|
|
func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
|
2015-07-08 07:06:48 -04:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2016-09-21 14:45:25 -04:00
|
|
|
func (daemon *Daemon) getLayerInit() func(string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-05-15 19:34:26 -04:00
|
|
|
func checkKernel() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-02-18 05:10:31 -05:00
|
|
|
func (daemon *Daemon) getCgroupDriver() string {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2015-07-30 18:28:11 -04:00
|
|
|
// adaptContainerSettings is called during container creation to modify any
|
|
|
|
// settings necessary in the HostConfig structure.
|
2015-12-18 13:36:17 -05:00
|
|
|
func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
|
2015-09-24 15:10:41 -04:00
|
|
|
if hostConfig == nil {
|
2015-12-01 21:53:52 -05:00
|
|
|
return nil
|
2015-09-24 15:10:41 -04:00
|
|
|
}
|
|
|
|
|
2015-12-01 21:53:52 -05:00
|
|
|
return nil
|
2015-07-13 03:17:43 -04:00
|
|
|
}
|
|
|
|
|
2016-11-01 16:02:46 -04:00
|
|
|
func verifyContainerResources(resources *containertypes.Resources, isHyperv bool) ([]string, error) {
|
2016-03-04 20:24:09 -05:00
|
|
|
warnings := []string{}
|
|
|
|
|
2016-11-01 16:02:46 -04:00
|
|
|
if !isHyperv {
|
|
|
|
// The processor resource controls are mutually exclusive on
|
|
|
|
// Windows Server Containers, the order of precedence is
|
|
|
|
// CPUCount first, then CPUShares, and CPUPercent last.
|
|
|
|
if resources.CPUCount > 0 {
|
|
|
|
if resources.CPUShares > 0 {
|
|
|
|
warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
|
|
|
logrus.Warn("Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
|
|
|
|
resources.CPUShares = 0
|
|
|
|
}
|
|
|
|
if resources.CPUPercent > 0 {
|
|
|
|
warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
|
|
logrus.Warn("Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
|
|
resources.CPUPercent = 0
|
|
|
|
}
|
|
|
|
} else if resources.CPUShares > 0 {
|
|
|
|
if resources.CPUPercent > 0 {
|
|
|
|
warnings = append(warnings, "Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
|
|
logrus.Warn("Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
|
|
|
|
resources.CPUPercent = 0
|
|
|
|
}
|
|
|
|
}
|
2016-03-04 20:24:09 -05:00
|
|
|
}
|
|
|
|
|
2016-11-09 18:18:54 -05:00
|
|
|
if resources.CPUShares < 0 || resources.CPUShares > windowsMaxCPUShares {
|
|
|
|
return warnings, fmt.Errorf("range of CPUShares is from %d to %d", windowsMinCPUShares, windowsMaxCPUShares)
|
|
|
|
}
|
|
|
|
if resources.CPUPercent < 0 || resources.CPUPercent > windowsMaxCPUPercent {
|
|
|
|
return warnings, fmt.Errorf("range of CPUPercent is from %d to %d", windowsMinCPUPercent, windowsMaxCPUPercent)
|
|
|
|
}
|
|
|
|
if resources.CPUCount < 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid CPUCount: CPUCount cannot be negative")
|
2016-11-01 13:12:29 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 18:18:54 -05:00
|
|
|
if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
|
|
|
|
return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Percent cannot both be set")
|
|
|
|
}
|
2016-11-01 13:12:29 -04:00
|
|
|
if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
|
2016-11-09 18:18:54 -05:00
|
|
|
return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
|
2016-11-01 13:12:29 -04:00
|
|
|
}
|
2016-11-15 18:48:46 -05:00
|
|
|
// The precision we could get is 0.01, because on Windows we have to convert to CPUPercent.
|
|
|
|
// We don't set the lower limit here and it is up to the underlying platform (e.g., Windows) to return an error.
|
2016-11-01 13:12:29 -04:00
|
|
|
if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
|
2016-11-15 18:48:46 -05:00
|
|
|
return warnings, fmt.Errorf("range of CPUs is from 0.01 to %d.00, as there are only %d CPUs available", sysinfo.NumCPU(), sysinfo.NumCPU())
|
2016-11-01 13:12:29 -04:00
|
|
|
}
|
|
|
|
|
2016-11-09 18:18:54 -05:00
|
|
|
if len(resources.BlkioDeviceReadBps) > 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadBps")
|
|
|
|
}
|
|
|
|
if len(resources.BlkioDeviceReadIOps) > 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadIOps")
|
|
|
|
}
|
|
|
|
if len(resources.BlkioDeviceWriteBps) > 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteBps")
|
|
|
|
}
|
|
|
|
if len(resources.BlkioDeviceWriteIOps) > 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteIOps")
|
|
|
|
}
|
2016-02-24 20:51:46 -05:00
|
|
|
if resources.BlkioWeight > 0 {
|
2016-11-09 18:18:54 -05:00
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeight")
|
2016-02-24 20:51:46 -05:00
|
|
|
}
|
|
|
|
if len(resources.BlkioWeightDevice) > 0 {
|
2016-11-09 18:18:54 -05:00
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeightDevice")
|
2016-02-24 20:51:46 -05:00
|
|
|
}
|
2016-11-09 18:18:54 -05:00
|
|
|
if resources.CgroupParent != "" {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CgroupParent")
|
2016-02-24 20:51:46 -05:00
|
|
|
}
|
2016-11-09 18:18:54 -05:00
|
|
|
if resources.CPUPeriod != 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CPUPeriod")
|
2016-02-24 20:51:46 -05:00
|
|
|
}
|
2016-11-09 18:18:54 -05:00
|
|
|
if resources.CpusetCpus != "" {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CpusetCpus")
|
2016-02-24 20:51:46 -05:00
|
|
|
}
|
2016-11-09 18:18:54 -05:00
|
|
|
if resources.CpusetMems != "" {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support CpusetMems")
|
|
|
|
}
|
|
|
|
if resources.KernelMemory != 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support KernelMemory")
|
|
|
|
}
|
|
|
|
if resources.MemoryReservation != 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support MemoryReservation")
|
|
|
|
}
|
|
|
|
if resources.MemorySwap != 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwap")
|
|
|
|
}
|
|
|
|
if resources.MemorySwappiness != nil && *resources.MemorySwappiness != -1 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwappiness")
|
|
|
|
}
|
|
|
|
if resources.OomKillDisable != nil && *resources.OomKillDisable {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support OomKillDisable")
|
|
|
|
}
|
|
|
|
if resources.PidsLimit != 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support PidsLimit")
|
|
|
|
}
|
|
|
|
if len(resources.Ulimits) != 0 {
|
|
|
|
return warnings, fmt.Errorf("invalid option: Windows does not support Ulimits")
|
2016-02-24 20:51:46 -05:00
|
|
|
}
|
2016-03-04 20:24:09 -05:00
|
|
|
return warnings, nil
|
|
|
|
}
|
|
|
|
|
2015-07-30 18:28:11 -04:00
|
|
|
// verifyPlatformContainerSettings performs platform-specific validation of the
|
|
|
|
// hostconfig and config structures.
|
2016-02-24 00:36:47 -05:00
|
|
|
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
|
2016-03-04 20:24:09 -05:00
|
|
|
warnings := []string{}
|
|
|
|
|
2016-11-10 17:35:19 -05:00
|
|
|
hyperv := daemon.runAsHyperVContainer(hostConfig)
|
|
|
|
if !hyperv && system.IsWindowsClient() {
|
|
|
|
// @engine maintainers. This block should not be removed. It partially enforces licensing
|
|
|
|
// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
|
|
|
|
return warnings, fmt.Errorf("Windows client operating systems only support Hyper-V containers")
|
|
|
|
}
|
|
|
|
|
|
|
|
w, err := verifyContainerResources(&hostConfig.Resources, hyperv)
|
2016-03-04 20:24:09 -05:00
|
|
|
warnings = append(warnings, w...)
|
2016-12-14 15:36:58 -05:00
|
|
|
return warnings, err
|
2015-05-15 19:34:26 -04:00
|
|
|
}
|
|
|
|
|
2017-01-07 09:30:25 -05:00
|
|
|
// reloadPlatform updates configuration with platform specific options
|
|
|
|
// and updates the passed attributes
|
|
|
|
func (daemon *Daemon) reloadPlatform(config *config.Config, attributes map[string]string) {
|
2016-05-23 17:49:50 -04:00
|
|
|
}
|
|
|
|
|
2016-01-22 21:15:09 -05:00
|
|
|
// verifyDaemonSettings performs validation of daemon config struct
|
2017-01-23 06:23:07 -05:00
|
|
|
func verifyDaemonSettings(config *config.Config) error {
|
2015-05-15 19:34:26 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-07-11 15:32:08 -04:00
|
|
|
// checkSystem validates platform-specific requirements
|
2015-05-15 19:34:26 -04:00
|
|
|
func checkSystem() error {
|
|
|
|
// Validate the OS version. Note that docker.exe must be manifested for this
|
|
|
|
// call to return the correct version.
|
2016-03-16 21:45:40 -04:00
|
|
|
osv := system.GetOSVersion()
|
2015-10-15 14:40:14 -04:00
|
|
|
if osv.MajorVersion < 10 {
|
2015-05-15 19:34:26 -04:00
|
|
|
return fmt.Errorf("This version of Windows does not support the docker daemon")
|
|
|
|
}
|
2016-09-15 18:20:16 -04:00
|
|
|
if osv.Build < 14393 {
|
|
|
|
return fmt.Errorf("The docker daemon requires build 14393 or later of Windows Server 2016 or Windows 10")
|
2015-11-11 17:47:02 -05:00
|
|
|
}
|
2016-11-18 15:34:25 -05:00
|
|
|
|
|
|
|
vmcompute := windows.NewLazySystemDLL("vmcompute.dll")
|
|
|
|
if vmcompute.Load() != nil {
|
|
|
|
return fmt.Errorf("Failed to load vmcompute.dll. Ensure that the Containers role is installed.")
|
|
|
|
}
|
2017-02-01 13:52:16 -05:00
|
|
|
|
|
|
|
return waitOOBEComplete()
|
2015-05-15 19:34:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// configureKernelSecuritySupport configures and validate security support for the kernel
|
2017-01-23 06:23:07 -05:00
|
|
|
func configureKernelSecuritySupport(config *config.Config, driverName string) error {
|
2015-05-15 19:34:26 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-12-02 05:26:30 -05:00
|
|
|
// configureMaxThreads sets the Go runtime max threads threshold
|
2017-01-23 06:23:07 -05:00
|
|
|
func configureMaxThreads(config *config.Config) error {
|
2015-12-02 05:26:30 -05:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
func (daemon *Daemon) initNetworkController(config *config.Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
|
2016-09-26 13:08:52 -04:00
|
|
|
netOptions, err := daemon.networkOptions(config, nil, nil)
|
2016-03-09 23:33:21 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
controller, err := libnetwork.New(netOptions...)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error obtaining controller instance: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove networks not present in HNS
|
|
|
|
for _, v := range controller.Networks() {
|
|
|
|
options := v.Info().DriverOptions()
|
|
|
|
hnsid := options[winlibnetwork.HNSID]
|
|
|
|
found := false
|
|
|
|
|
|
|
|
for _, v := range hnsresponse {
|
|
|
|
if v.Id == hnsid {
|
|
|
|
found = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !found {
|
2016-11-09 20:54:15 -05:00
|
|
|
// global networks should not be deleted by local HNS
|
|
|
|
if v.Info().Scope() != datastore.GlobalScope {
|
|
|
|
err = v.Delete()
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("Error occurred when removing network %v", err)
|
|
|
|
}
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-05-08 03:33:16 -04:00
|
|
|
_, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
|
2016-03-09 23:33:21 -05:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2016-06-09 15:09:13 -04:00
|
|
|
defaultNetworkExists := false
|
|
|
|
|
|
|
|
if network, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
|
|
|
|
options := network.Info().DriverOptions()
|
|
|
|
for _, v := range hnsresponse {
|
|
|
|
if options[winlibnetwork.HNSID] == v.Id {
|
|
|
|
defaultNetworkExists = true
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 23:33:21 -05:00
|
|
|
// discover and add HNS networks to windows
|
|
|
|
// network that exist are removed and added again
|
|
|
|
for _, v := range hnsresponse {
|
|
|
|
var n libnetwork.Network
|
|
|
|
s := func(current libnetwork.Network) bool {
|
|
|
|
options := current.Info().DriverOptions()
|
|
|
|
if options[winlibnetwork.HNSID] == v.Id {
|
|
|
|
n = current
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
controller.WalkNetworks(s)
|
|
|
|
if n != nil {
|
2016-11-09 20:54:15 -05:00
|
|
|
// global networks should not be deleted by local HNS
|
|
|
|
if n.Info().Scope() == datastore.GlobalScope {
|
|
|
|
continue
|
|
|
|
}
|
2016-03-09 23:33:21 -05:00
|
|
|
v.Name = n.Name()
|
2016-06-09 15:09:13 -04:00
|
|
|
// This will not cause network delete from HNS as the network
|
|
|
|
// is not yet populated in the libnetwork windows driver
|
2016-03-09 23:33:21 -05:00
|
|
|
n.Delete()
|
|
|
|
}
|
|
|
|
|
|
|
|
netOption := map[string]string{
|
|
|
|
winlibnetwork.NetworkName: v.Name,
|
|
|
|
winlibnetwork.HNSID: v.Id,
|
|
|
|
}
|
|
|
|
|
|
|
|
v4Conf := []*libnetwork.IpamConf{}
|
|
|
|
for _, subnet := range v.Subnets {
|
|
|
|
ipamV4Conf := libnetwork.IpamConf{}
|
|
|
|
ipamV4Conf.PreferredPool = subnet.AddressPrefix
|
|
|
|
ipamV4Conf.Gateway = subnet.GatewayAddress
|
|
|
|
v4Conf = append(v4Conf, &ipamV4Conf)
|
|
|
|
}
|
|
|
|
|
|
|
|
name := v.Name
|
2016-06-09 15:09:13 -04:00
|
|
|
|
|
|
|
// If there is no nat network create one from the first NAT network
|
2017-01-13 00:09:57 -05:00
|
|
|
// encountered if it doesn't already exist
|
|
|
|
if !defaultNetworkExists &&
|
|
|
|
runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) &&
|
|
|
|
n == nil {
|
2016-03-09 23:33:21 -05:00
|
|
|
name = runconfig.DefaultDaemonNetworkMode().NetworkName()
|
2016-06-09 15:09:13 -04:00
|
|
|
defaultNetworkExists = true
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
v6Conf := []*libnetwork.IpamConf{}
|
2016-05-08 03:33:16 -04:00
|
|
|
_, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
|
2016-03-09 23:33:21 -05:00
|
|
|
libnetwork.NetworkOptionGeneric(options.Generic{
|
|
|
|
netlabel.GenericData: netOption,
|
|
|
|
}),
|
|
|
|
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
logrus.Errorf("Error occurred when creating network %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if !config.DisableBridge {
|
|
|
|
// Initialize default driver "bridge"
|
|
|
|
if err := initBridgeDriver(controller, config); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return controller, nil
|
2015-05-15 19:34:26 -04:00
|
|
|
}
|
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error {
|
2016-03-09 23:33:21 -05:00
|
|
|
if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
|
|
|
|
return nil
|
2015-07-13 15:34:58 -04:00
|
|
|
}
|
2016-03-09 23:33:21 -05:00
|
|
|
|
|
|
|
netOption := map[string]string{
|
|
|
|
winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
|
|
|
|
}
|
|
|
|
|
2016-06-09 15:09:13 -04:00
|
|
|
var ipamOption libnetwork.NetworkOption
|
|
|
|
var subnetPrefix string
|
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
if config.BridgeConfig.FixedCIDR != "" {
|
|
|
|
subnetPrefix = config.BridgeConfig.FixedCIDR
|
2016-03-09 23:33:21 -05:00
|
|
|
} else {
|
2016-06-09 15:09:13 -04:00
|
|
|
// TP5 doesn't support properly detecting subnet
|
|
|
|
osv := system.GetOSVersion()
|
|
|
|
if osv.Build < 14360 {
|
|
|
|
subnetPrefix = defaultNetworkSpace
|
|
|
|
}
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
|
2016-06-09 15:09:13 -04:00
|
|
|
if subnetPrefix != "" {
|
|
|
|
ipamV4Conf := libnetwork.IpamConf{}
|
|
|
|
ipamV4Conf.PreferredPool = subnetPrefix
|
|
|
|
v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
|
|
|
|
v6Conf := []*libnetwork.IpamConf{}
|
|
|
|
ipamOption = libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil)
|
|
|
|
}
|
2016-03-09 23:33:21 -05:00
|
|
|
|
2016-05-08 03:33:16 -04:00
|
|
|
_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
|
2016-03-09 23:33:21 -05:00
|
|
|
libnetwork.NetworkOptionGeneric(options.Generic{
|
|
|
|
netlabel.GenericData: netOption,
|
|
|
|
}),
|
2016-06-09 15:09:13 -04:00
|
|
|
ipamOption,
|
2016-03-09 23:33:21 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating default network: %v", err)
|
|
|
|
}
|
2016-06-09 15:09:13 -04:00
|
|
|
|
2016-03-09 23:33:21 -05:00
|
|
|
return nil
|
2015-05-15 19:34:26 -04:00
|
|
|
}
|
2015-06-23 13:13:42 -04:00
|
|
|
|
2015-07-30 17:01:53 -04:00
|
|
|
// registerLinks sets up links between containers and writes the
|
2015-11-16 00:32:31 -05:00
|
|
|
// configuration out for persistence. As of Windows TP4, links are not supported.
|
2015-12-18 13:36:17 -05:00
|
|
|
func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
2015-06-23 13:13:42 -04:00
|
|
|
return nil
|
|
|
|
}
|
2015-07-16 17:14:58 -04:00
|
|
|
|
2016-03-18 14:53:27 -04:00
|
|
|
func (daemon *Daemon) cleanupMountsByID(in string) error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-08-03 18:05:34 -04:00
|
|
|
func (daemon *Daemon) cleanupMounts() error {
|
|
|
|
return nil
|
|
|
|
}
|
2015-11-02 20:06:09 -05:00
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
func setupRemappedRoot(config *config.Config) ([]idtools.IDMap, []idtools.IDMap, error) {
|
2016-01-07 22:43:11 -05:00
|
|
|
return nil, nil, nil
|
|
|
|
}
|
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
func setupDaemonRoot(config *config.Config, rootDir string, rootUID, rootGID int) error {
|
2016-01-07 22:43:11 -05:00
|
|
|
config.Root = rootDir
|
|
|
|
// Create the root directory if it doesn't exists
|
2016-11-04 15:42:21 -04:00
|
|
|
if err := system.MkdirAllWithACL(config.Root, 0); err != nil && !os.IsExist(err) {
|
2016-01-07 22:43:11 -05:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2016-03-18 23:09:54 -04:00
|
|
|
// runasHyperVContainer returns true if we are going to run as a Hyper-V container
|
2016-11-01 16:02:46 -04:00
|
|
|
func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
|
|
|
|
if hostConfig.Isolation.IsDefault() {
|
2016-03-18 14:53:27 -04:00
|
|
|
// Container is set to use the default, so take the default from the daemon configuration
|
2016-03-18 23:09:54 -04:00
|
|
|
return daemon.defaultIsolation.IsHyperV()
|
2016-03-18 14:53:27 -04:00
|
|
|
}
|
|
|
|
|
2016-03-18 23:09:54 -04:00
|
|
|
// Container is requesting an isolation mode. Honour it.
|
2016-11-01 16:02:46 -04:00
|
|
|
return hostConfig.Isolation.IsHyperV()
|
2016-03-18 23:09:54 -04:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// conditionalMountOnStart is a platform specific helper function during the
|
|
|
|
// container start to call mount.
|
|
|
|
func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
|
2015-11-02 20:06:09 -05:00
|
|
|
// We do not mount if a Hyper-V container
|
2016-11-01 16:02:46 -04:00
|
|
|
if !daemon.runAsHyperVContainer(container.HostConfig) {
|
2016-03-18 23:09:54 -04:00
|
|
|
return daemon.Mount(container)
|
2015-11-02 20:06:09 -05:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// conditionalUnmountOnCleanup is a platform specific helper function called
|
|
|
|
// during the cleanup of a container to unmount.
|
2016-03-18 14:53:27 -04:00
|
|
|
func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
|
2015-11-02 20:06:09 -05:00
|
|
|
// We do not unmount if a Hyper-V container
|
2016-11-01 16:02:46 -04:00
|
|
|
if !daemon.runAsHyperVContainer(container.HostConfig) {
|
2016-03-18 14:53:27 -04:00
|
|
|
return daemon.Unmount(container)
|
2015-11-18 17:20:54 -05:00
|
|
|
}
|
2016-03-18 14:53:27 -04:00
|
|
|
return nil
|
2015-11-18 17:20:54 -05:00
|
|
|
}
|
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
func driverOptions(config *config.Config) []nwconfig.Option {
|
2016-03-09 23:33:21 -05:00
|
|
|
return []nwconfig.Option{}
|
2016-02-17 20:08:11 -05:00
|
|
|
}
|
2016-03-18 14:53:27 -04:00
|
|
|
|
|
|
|
func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
|
2016-09-07 19:08:51 -04:00
|
|
|
if !c.IsRunning() {
|
|
|
|
return nil, errNotRunning{c.ID}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Obtain the stats from HCS via libcontainerd
|
|
|
|
stats, err := daemon.containerd.Stats(c.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start with an empty structure
|
|
|
|
s := &types.StatsJSON{}
|
|
|
|
|
|
|
|
// Populate the CPU/processor statistics
|
|
|
|
s.CPUStats = types.CPUStats{
|
|
|
|
CPUUsage: types.CPUUsage{
|
|
|
|
TotalUsage: stats.Processor.TotalRuntime100ns,
|
|
|
|
UsageInKernelmode: stats.Processor.RuntimeKernel100ns,
|
|
|
|
UsageInUsermode: stats.Processor.RuntimeKernel100ns,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate the memory statistics
|
|
|
|
s.MemoryStats = types.MemoryStats{
|
|
|
|
Commit: stats.Memory.UsageCommitBytes,
|
|
|
|
CommitPeak: stats.Memory.UsageCommitPeakBytes,
|
|
|
|
PrivateWorkingSet: stats.Memory.UsagePrivateWorkingSetBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate the storage statistics
|
|
|
|
s.StorageStats = types.StorageStats{
|
|
|
|
ReadCountNormalized: stats.Storage.ReadCountNormalized,
|
|
|
|
ReadSizeBytes: stats.Storage.ReadSizeBytes,
|
|
|
|
WriteCountNormalized: stats.Storage.WriteCountNormalized,
|
|
|
|
WriteSizeBytes: stats.Storage.WriteSizeBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate the network statistics
|
|
|
|
s.Networks = make(map[string]types.NetworkStats)
|
|
|
|
|
|
|
|
for _, nstats := range stats.Network {
|
|
|
|
s.Networks[nstats.EndpointId] = types.NetworkStats{
|
|
|
|
RxBytes: nstats.BytesReceived,
|
|
|
|
RxPackets: nstats.PacketsReceived,
|
|
|
|
RxDropped: nstats.DroppedPacketsIncoming,
|
|
|
|
TxBytes: nstats.BytesSent,
|
|
|
|
TxPackets: nstats.PacketsSent,
|
|
|
|
TxDropped: nstats.DroppedPacketsOutgoing,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set the timestamp
|
|
|
|
s.Stats.Read = stats.Timestamp
|
|
|
|
s.Stats.NumProcs = platform.NumProcs()
|
|
|
|
|
|
|
|
return s, nil
|
2016-03-18 14:53:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// setDefaultIsolation determine the default isolation mode for the
|
|
|
|
// daemon to run in. This is only applicable on Windows
|
|
|
|
func (daemon *Daemon) setDefaultIsolation() error {
|
|
|
|
daemon.defaultIsolation = containertypes.Isolation("process")
|
2016-04-14 20:12:02 -04:00
|
|
|
// On client SKUs, default to Hyper-V
|
|
|
|
if system.IsWindowsClient() {
|
|
|
|
daemon.defaultIsolation = containertypes.Isolation("hyperv")
|
|
|
|
}
|
2016-03-18 14:53:27 -04:00
|
|
|
for _, option := range daemon.configStore.ExecOptions {
|
|
|
|
key, val, err := parsers.ParseKeyValueOpt(option)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
key = strings.ToLower(key)
|
|
|
|
switch key {
|
|
|
|
|
|
|
|
case "isolation":
|
|
|
|
if !containertypes.Isolation(val).IsValid() {
|
|
|
|
return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val)
|
|
|
|
}
|
|
|
|
if containertypes.Isolation(val).IsHyperV() {
|
|
|
|
daemon.defaultIsolation = containertypes.Isolation("hyperv")
|
|
|
|
}
|
2016-04-14 20:12:02 -04:00
|
|
|
if containertypes.Isolation(val).IsProcess() {
|
|
|
|
if system.IsWindowsClient() {
|
2016-10-25 13:30:00 -04:00
|
|
|
// @engine maintainers. This block should not be removed. It partially enforces licensing
|
|
|
|
// restrictions on Windows. Ping @jhowardmsft if there are concerns or PRs to change this.
|
2016-04-14 20:12:02 -04:00
|
|
|
return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
|
|
|
|
}
|
|
|
|
daemon.defaultIsolation = containertypes.Isolation("process")
|
|
|
|
}
|
2016-03-18 14:53:27 -04:00
|
|
|
default:
|
|
|
|
return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
|
|
|
|
return nil
|
|
|
|
}
|
2016-03-21 12:56:51 -04:00
|
|
|
|
|
|
|
func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
|
|
|
|
var layers []string
|
|
|
|
for _, l := range rootfs.DiffIDs {
|
|
|
|
layers = append(layers, l.String())
|
|
|
|
}
|
|
|
|
return types.RootFS{
|
2016-07-22 18:29:21 -04:00
|
|
|
Type: rootfs.Type,
|
|
|
|
Layers: layers,
|
2016-03-21 12:56:51 -04:00
|
|
|
}
|
|
|
|
}
|
2016-07-11 18:26:23 -04:00
|
|
|
|
2017-01-23 06:23:07 -05:00
|
|
|
func setupDaemonProcess(config *config.Config) error {
|
2016-07-11 18:26:23 -04:00
|
|
|
return nil
|
|
|
|
}
|
2016-09-06 09:49:10 -04:00
|
|
|
|
|
|
|
// verifyVolumesInfo is a no-op on windows.
|
|
|
|
// This is called during daemon initialization to migrate volumes from pre-1.7.
|
|
|
|
// volumes were not supported on windows pre-1.7
|
|
|
|
func (daemon *Daemon) verifyVolumesInfo(container *container.Container) error {
|
|
|
|
return nil
|
|
|
|
}
|
2016-09-02 09:20:54 -04:00
|
|
|
|
|
|
|
func (daemon *Daemon) setupSeccompProfile() error {
|
|
|
|
return nil
|
|
|
|
}
|
2017-02-01 13:52:16 -05:00
|
|
|
|
|
|
|
func waitOOBEComplete() error {
|
|
|
|
kernel32 := windows.NewLazySystemDLL("kernel32.dll")
|
|
|
|
registerWaitUntilOOBECompleted := kernel32.NewProc("RegisterWaitUntilOOBECompleted")
|
|
|
|
unregisterWaitUntilOOBECompleted := kernel32.NewProc("UnregisterWaitUntilOOBECompleted")
|
|
|
|
|
|
|
|
callbackChan := make(chan struct{})
|
|
|
|
callbackFunc := func(uintptr) uintptr {
|
|
|
|
close(callbackChan)
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
callbackFuncPtr := syscall.NewCallback(callbackFunc)
|
|
|
|
|
|
|
|
var callbackHandle syscall.Handle
|
|
|
|
ret, _, err := registerWaitUntilOOBECompleted.Call(callbackFuncPtr, 0, uintptr(unsafe.Pointer(&callbackHandle)))
|
|
|
|
if ret == 0 {
|
|
|
|
if err == errInvalidState {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return fmt.Errorf("failed to register OOBEComplete callback. Error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Wait for the callback when OOBE is finished
|
|
|
|
<-callbackChan
|
|
|
|
|
|
|
|
ret, _, err = unregisterWaitUntilOOBECompleted.Call(uintptr(callbackHandle))
|
|
|
|
if ret == 0 {
|
|
|
|
return fmt.Errorf("failed to unregister OOBEComplete callback. Error: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|