2018-02-05 16:05:59 -05:00
|
|
|
package daemon // import "github.com/docker/docker/daemon"
|
2015-05-15 19:34:26 -04:00
|
|
|
|
|
|
|
import (
|
2017-09-22 09:52:41 -04:00
|
|
|
"context"
|
2015-05-15 19:34:26 -04:00
|
|
|
"fmt"
|
2019-08-13 03:10:19 -04:00
|
|
|
"math"
|
2017-02-02 14:22:12 -05:00
|
|
|
"path/filepath"
|
2019-08-13 03:10:19 -04:00
|
|
|
"runtime"
|
2015-11-18 17:20:54 -05:00
|
|
|
"strings"
|
2015-05-15 19:34:26 -04:00
|
|
|
|
2016-03-09 23:33:21 -05:00
|
|
|
"github.com/Microsoft/hcsshim"
|
2019-04-17 06:39:07 -04:00
|
|
|
"github.com/Microsoft/hcsshim/osversion"
|
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"
|
2021-02-26 18:23:55 -05:00
|
|
|
"github.com/docker/docker/libcontainerd/local"
|
|
|
|
"github.com/docker/docker/libcontainerd/remote"
|
2021-05-27 20:15:56 -04:00
|
|
|
"github.com/docker/docker/libnetwork"
|
|
|
|
nwconfig "github.com/docker/docker/libnetwork/config"
|
|
|
|
"github.com/docker/docker/libnetwork/datastore"
|
|
|
|
winlibnetwork "github.com/docker/docker/libnetwork/drivers/windows"
|
|
|
|
"github.com/docker/docker/libnetwork/netlabel"
|
|
|
|
"github.com/docker/docker/libnetwork/options"
|
2017-08-03 20:22:00 -04:00
|
|
|
"github.com/docker/docker/pkg/containerfs"
|
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"
|
2022-03-15 19:41:30 -04:00
|
|
|
"github.com/docker/docker/pkg/parsers/operatingsystem"
|
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"
|
2017-09-21 18:09:41 -04:00
|
|
|
"github.com/pkg/errors"
|
2017-07-26 17:42:13 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2016-11-18 15:34:25 -05:00
|
|
|
"golang.org/x/sys/windows"
|
2017-09-21 18:09:41 -04:00
|
|
|
"golang.org/x/sys/windows/svc/mgr"
|
2015-05-15 19:34:26 -04:00
|
|
|
)
|
|
|
|
|
2015-08-07 12:33:29 -04:00
|
|
|
const (
|
2019-10-12 20:29:21 -04:00
|
|
|
isWindows = true
|
2016-11-01 16:02:46 -04:00
|
|
|
platformSupported = true
|
|
|
|
windowsMinCPUShares = 1
|
|
|
|
windowsMaxCPUShares = 10000
|
|
|
|
windowsMinCPUPercent = 1
|
|
|
|
windowsMaxCPUPercent = 100
|
2021-02-26 18:23:55 -05:00
|
|
|
|
|
|
|
windowsV1RuntimeName = "com.docker.hcsshim.v1"
|
|
|
|
windowsV2RuntimeName = "io.containerd.runhcs.v1"
|
2015-08-07 12:33:29 -04:00
|
|
|
)
|
2015-07-13 15:34:58 -04:00
|
|
|
|
2019-08-13 03:10:19 -04:00
|
|
|
// Windows containers are much larger than Linux containers and each of them
|
|
|
|
// have > 20 system processes which why we use much smaller parallelism value.
|
2018-12-04 11:44:45 -05:00
|
|
|
func adjustParallelLimit(n int, limit int) int {
|
2019-08-13 03:10:19 -04:00
|
|
|
return int(math.Max(1, math.Floor(float64(runtime.NumCPU())*.8)))
|
2018-12-04 11:44:45 -05: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")
|
|
|
|
}
|
|
|
|
|
2017-01-08 20:22:05 -05:00
|
|
|
func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
|
2015-05-15 19:34:26 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-03-14 15:24:29 -04:00
|
|
|
func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error {
|
2016-09-21 14:45:25 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
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-12-01 21:53:52 -05:00
|
|
|
return nil
|
2015-07-13 03:17:43 -04:00
|
|
|
}
|
|
|
|
|
2018-12-18 17:41:52 -05:00
|
|
|
// verifyPlatformContainerResources performs platform-specific validation of the container's resource-configuration
|
|
|
|
func verifyPlatformContainerResources(resources *containertypes.Resources, isHyperv bool) (warnings []string, err error) {
|
2017-06-30 13:34:40 -04:00
|
|
|
fixMemorySwappiness(resources)
|
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")
|
|
|
|
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")
|
|
|
|
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")
|
|
|
|
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")
|
|
|
|
}
|
2017-06-30 13:34:40 -04:00
|
|
|
if resources.MemorySwappiness != nil {
|
2016-11-09 18:18:54 -05:00
|
|
|
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")
|
|
|
|
}
|
2017-04-11 07:28:13 -04:00
|
|
|
if resources.PidsLimit != nil && *resources.PidsLimit != 0 {
|
2016-11-09 18:18:54 -05:00
|
|
|
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.
|
2018-12-18 17:20:17 -05:00
|
|
|
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, update bool) (warnings []string, err error) {
|
2018-12-18 19:28:08 -05:00
|
|
|
if hostConfig == nil {
|
|
|
|
return nil, nil
|
|
|
|
}
|
2022-02-17 11:08:46 -05:00
|
|
|
return verifyPlatformContainerResources(&hostConfig.Resources, daemon.runAsHyperVContainer(hostConfig))
|
2015-05-15 19:34:26 -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 {
|
2019-09-11 09:16:27 -04:00
|
|
|
// Validate the OS version. Note that dockerd.exe must be manifested for this
|
2015-05-15 19:34:26 -04:00
|
|
|
// call to return the correct version.
|
2022-02-17 11:08:46 -05:00
|
|
|
if osversion.Get().MajorVersion < 10 || osversion.Build() < osversion.RS5 {
|
|
|
|
return fmt.Errorf("this version of Windows does not support the docker daemon (Windows build %d or higher is required)", osversion.RS5)
|
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 {
|
2017-09-25 15:39:27 -04:00
|
|
|
return fmt.Errorf("failed to load vmcompute.dll, ensure that the Containers feature is installed")
|
2016-11-18 15:34:25 -05:00
|
|
|
}
|
2017-02-01 13:52:16 -05:00
|
|
|
|
2017-09-21 18:09:41 -04:00
|
|
|
// Ensure that the required Host Network Service and vmcompute services
|
|
|
|
// are running. Docker will fail in unexpected ways if this is not present.
|
|
|
|
var requiredServices = []string{"hns", "vmcompute"}
|
|
|
|
if err := ensureServicesInstalled(requiredServices); err != nil {
|
|
|
|
return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ensureServicesInstalled(services []string) error {
|
|
|
|
m, err := mgr.Connect()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer m.Disconnect()
|
|
|
|
for _, service := range services {
|
|
|
|
s, err := m.OpenService(service)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrapf(err, "failed to open service %s", service)
|
|
|
|
}
|
|
|
|
s.Close()
|
|
|
|
}
|
2017-03-27 17:32:18 -04:00
|
|
|
return nil
|
2015-05-15 19:34:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// configureKernelSecuritySupport configures and validate security support for the kernel
|
2017-08-24 14:48:16 -04: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
|
|
|
|
}
|
|
|
|
|
2022-04-26 04:32:10 -04:00
|
|
|
func (daemon *Daemon) initNetworkController(activeSandboxes map[string]interface{}) error {
|
2022-04-23 17:12:55 -04:00
|
|
|
netOptions, err := daemon.networkOptions(nil, nil)
|
2016-03-09 23:33:21 -05:00
|
|
|
if err != nil {
|
2022-04-26 04:32:10 -04:00
|
|
|
return err
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
2022-04-26 04:32:10 -04:00
|
|
|
daemon.netController, err = libnetwork.New(netOptions...)
|
2016-03-09 23:33:21 -05:00
|
|
|
if err != nil {
|
2022-04-26 04:32:10 -04:00
|
|
|
return errors.Wrap(err, "error obtaining controller instance")
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
|
|
|
|
if err != nil {
|
2022-04-26 04:32:10 -04:00
|
|
|
return err
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Remove networks not present in HNS
|
2022-04-26 04:32:10 -04:00
|
|
|
for _, v := range daemon.netController.Networks() {
|
2022-04-23 17:12:55 -04:00
|
|
|
hnsid := v.Info().DriverOptions()[winlibnetwork.HNSID]
|
2016-03-09 23:33:21 -05:00
|
|
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 04:32:10 -04:00
|
|
|
_, err = daemon.netController.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
|
2016-03-09 23:33:21 -05:00
|
|
|
if err != nil {
|
2022-04-26 04:32:10 -04:00
|
|
|
return err
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
|
2016-06-09 15:09:13 -04:00
|
|
|
defaultNetworkExists := false
|
|
|
|
|
2022-04-26 04:32:10 -04:00
|
|
|
if network, err := daemon.netController.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
|
2022-04-23 17:12:55 -04:00
|
|
|
hnsid := network.Info().DriverOptions()[winlibnetwork.HNSID]
|
2016-06-09 15:09:13 -04:00
|
|
|
for _, v := range hnsresponse {
|
2022-04-23 17:12:55 -04:00
|
|
|
if hnsid == v.Id {
|
2016-06-09 15:09:13 -04:00
|
|
|
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 {
|
2018-09-06 05:54:23 -04:00
|
|
|
networkTypeNorm := strings.ToLower(v.Type)
|
|
|
|
if networkTypeNorm == "private" || networkTypeNorm == "internal" {
|
2017-05-05 12:03:22 -04:00
|
|
|
continue // workaround for HNS reporting unsupported networks
|
|
|
|
}
|
2016-03-09 23:33:21 -05:00
|
|
|
var n libnetwork.Network
|
|
|
|
s := func(current libnetwork.Network) bool {
|
2022-04-23 17:12:55 -04:00
|
|
|
hnsid := current.Info().DriverOptions()[winlibnetwork.HNSID]
|
|
|
|
if hnsid == v.Id {
|
2016-03-09 23:33:21 -05:00
|
|
|
n = current
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-04-26 04:32:10 -04:00
|
|
|
daemon.netController.WalkNetworks(s)
|
2017-11-21 15:00:26 -05:00
|
|
|
|
|
|
|
drvOptions := make(map[string]string)
|
2019-01-15 20:05:23 -05:00
|
|
|
nid := ""
|
2016-03-09 23:33:21 -05:00
|
|
|
if n != nil {
|
2019-01-15 20:05:23 -05:00
|
|
|
nid = n.ID()
|
|
|
|
|
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
|
2017-11-21 15:00:26 -05:00
|
|
|
|
|
|
|
// restore option if it existed before
|
|
|
|
drvOptions = n.Info().DriverOptions()
|
2016-03-09 23:33:21 -05:00
|
|
|
n.Delete()
|
|
|
|
}
|
|
|
|
netOption := map[string]string{
|
|
|
|
winlibnetwork.NetworkName: v.Name,
|
|
|
|
winlibnetwork.HNSID: v.Id,
|
|
|
|
}
|
|
|
|
|
2017-11-21 15:00:26 -05:00
|
|
|
// add persisted driver options
|
|
|
|
for k, v := range drvOptions {
|
|
|
|
if k != winlibnetwork.NetworkName && k != winlibnetwork.HNSID {
|
|
|
|
netOption[k] = v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-09 23:33:21 -05:00
|
|
|
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{}
|
2022-04-26 04:32:10 -04:00
|
|
|
_, err := daemon.netController.NewNetwork(strings.ToLower(v.Type), name, nid,
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 04:32:10 -04:00
|
|
|
if !daemon.configStore.DisableBridge {
|
2016-03-09 23:33:21 -05:00
|
|
|
// Initialize default driver "bridge"
|
2022-04-26 04:32:10 -04:00
|
|
|
if err := initBridgeDriver(daemon.netController, daemon.configStore); err != nil {
|
|
|
|
return err
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-26 04:32:10 -04:00
|
|
|
return 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(),
|
|
|
|
}
|
|
|
|
|
2019-11-06 13:54:28 -05: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
|
|
|
}
|
|
|
|
|
2019-11-06 13:54:28 -05:00
|
|
|
if subnetPrefix != "" {
|
|
|
|
ipamV4Conf := libnetwork.IpamConf{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 {
|
2022-04-26 04:32:10 -04:00
|
|
|
return errors.Wrap(err, "error creating default network")
|
2016-03-09 23:33:21 -05:00
|
|
|
}
|
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
|
2020-09-19 12:45:41 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func recursiveUnmount(_ string) error {
|
|
|
|
return nil
|
2015-08-03 18:05:34 -04:00
|
|
|
}
|
2015-11-02 20:06:09 -05:00
|
|
|
|
2022-03-14 15:24:29 -04:00
|
|
|
func setupRemappedRoot(config *config.Config) (idtools.IdentityMapping, error) {
|
|
|
|
return idtools.IdentityMapping{}, nil
|
2016-01-07 22:43:11 -05:00
|
|
|
}
|
|
|
|
|
2017-11-16 01:20:33 -05:00
|
|
|
func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
|
2016-01-07 22:43:11 -05:00
|
|
|
config.Root = rootDir
|
|
|
|
// Create the root directory if it doesn't exists
|
Simplify/fix MkdirAll usage
This subtle bug keeps lurking in because error checking for `Mkdir()`
and `MkdirAll()` is slightly different wrt to `EEXIST`/`IsExist`:
- for `Mkdir()`, `IsExist` error should (usually) be ignored
(unless you want to make sure directory was not there before)
as it means "the destination directory was already there"
- for `MkdirAll()`, `IsExist` error should NEVER be ignored.
Mostly, this commit just removes ignoring the IsExist error, as it
should not be ignored.
Also, there are a couple of cases then IsExist is handled as
"directory already exist" which is wrong. As a result, some code
that never worked as intended is now removed.
NOTE that `idtools.MkdirAndChown()` behaves like `os.MkdirAll()`
rather than `os.Mkdir()` -- so its description is amended accordingly,
and its usage is handled as such (i.e. IsExist error is not ignored).
For more details, a quote from my runc commit 6f82d4b (July 2015):
TL;DR: check for IsExist(err) after a failed MkdirAll() is both
redundant and wrong -- so two reasons to remove it.
Quoting MkdirAll documentation:
> MkdirAll creates a directory named path, along with any necessary
> parents, and returns nil, or else returns an error. If path
> is already a directory, MkdirAll does nothing and returns nil.
This means two things:
1. If a directory to be created already exists, no error is
returned.
2. If the error returned is IsExist (EEXIST), it means there exists
a non-directory with the same name as MkdirAll need to use for
directory. Example: we want to MkdirAll("a/b"), but file "a"
(or "a/b") already exists, so MkdirAll fails.
The above is a theory, based on quoted documentation and my UNIX
knowledge.
3. In practice, though, current MkdirAll implementation [1] returns
ENOTDIR in most of cases described in #2, with the exception when
there is a race between MkdirAll and someone else creating the
last component of MkdirAll argument as a file. In this very case
MkdirAll() will indeed return EEXIST.
Because of #1, IsExist check after MkdirAll is not needed.
Because of #2 and #3, ignoring IsExist error is just plain wrong,
as directory we require is not created. It's cleaner to report
the error now.
Note this error is all over the tree, I guess due to copy-paste,
or trying to follow the same usage pattern as for Mkdir(),
or some not quite correct examples on the Internet.
[1] https://github.com/golang/go/blob/f9ed2f75/src/os/path.go
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2017-09-25 15:39:36 -04:00
|
|
|
if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
|
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 {
|
2021-03-18 16:01:46 -04:00
|
|
|
if daemon.runAsHyperVContainer(container.HostConfig) {
|
|
|
|
// We do not mount if a Hyper-V container as it needs to be mounted inside the
|
|
|
|
// utility VM, not the host.
|
2017-06-16 23:28:18 -04:00
|
|
|
return nil
|
|
|
|
}
|
2021-03-18 16:01:46 -04:00
|
|
|
return daemon.Mount(container)
|
2015-11-02 20:06:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2021-07-27 06:12:11 -04:00
|
|
|
if daemon.runAsHyperVContainer(container.HostConfig) {
|
|
|
|
// We do not unmount if a Hyper-V container
|
2017-06-16 23:28:18 -04:00
|
|
|
return nil
|
|
|
|
}
|
2021-07-27 06:12:11 -04:00
|
|
|
return daemon.Unmount(container)
|
2015-11-18 17:20:54 -05:00
|
|
|
}
|
|
|
|
|
2021-07-27 06:12:11 -04:00
|
|
|
func driverOptions(_ *config.Config) nwconfig.Option {
|
|
|
|
return nil
|
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() {
|
2017-07-19 10:20:13 -04:00
|
|
|
return nil, errNotRunning(c.ID)
|
2016-09-07 19:08:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Obtain the stats from HCS via libcontainerd
|
2017-09-22 09:52:41 -04:00
|
|
|
stats, err := daemon.containerd.Stats(context.Background(), c.ID)
|
2016-09-07 19:08:51 -04:00
|
|
|
if err != nil {
|
2017-07-07 03:33:45 -04:00
|
|
|
if strings.Contains(err.Error(), "container not found") {
|
2017-07-19 10:20:13 -04:00
|
|
|
return nil, containerNotFound(c.ID)
|
2017-07-07 03:33:45 -04:00
|
|
|
}
|
2016-09-07 19:08:51 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Start with an empty structure
|
|
|
|
s := &types.StatsJSON{}
|
2017-09-22 09:52:41 -04:00
|
|
|
s.Stats.Read = stats.Read
|
|
|
|
s.Stats.NumProcs = platform.NumProcs()
|
2016-09-07 19:08:51 -04:00
|
|
|
|
2017-09-22 09:52:41 -04:00
|
|
|
if stats.HCSStats != nil {
|
|
|
|
hcss := stats.HCSStats
|
|
|
|
// Populate the CPU/processor statistics
|
|
|
|
s.CPUStats = types.CPUStats{
|
|
|
|
CPUUsage: types.CPUUsage{
|
|
|
|
TotalUsage: hcss.Processor.TotalRuntime100ns,
|
|
|
|
UsageInKernelmode: hcss.Processor.RuntimeKernel100ns,
|
2020-03-18 04:34:47 -04:00
|
|
|
UsageInUsermode: hcss.Processor.RuntimeUser100ns,
|
2017-09-22 09:52:41 -04:00
|
|
|
},
|
2016-09-07 19:08:51 -04:00
|
|
|
}
|
|
|
|
|
2017-09-22 09:52:41 -04:00
|
|
|
// Populate the memory statistics
|
|
|
|
s.MemoryStats = types.MemoryStats{
|
|
|
|
Commit: hcss.Memory.UsageCommitBytes,
|
|
|
|
CommitPeak: hcss.Memory.UsageCommitPeakBytes,
|
|
|
|
PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes,
|
|
|
|
}
|
2016-09-07 19:08:51 -04:00
|
|
|
|
2017-09-22 09:52:41 -04:00
|
|
|
// Populate the storage statistics
|
|
|
|
s.StorageStats = types.StorageStats{
|
|
|
|
ReadCountNormalized: hcss.Storage.ReadCountNormalized,
|
|
|
|
ReadSizeBytes: hcss.Storage.ReadSizeBytes,
|
|
|
|
WriteCountNormalized: hcss.Storage.WriteCountNormalized,
|
|
|
|
WriteSizeBytes: hcss.Storage.WriteSizeBytes,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Populate the network statistics
|
|
|
|
s.Networks = make(map[string]types.NetworkStats)
|
|
|
|
for _, nstats := range hcss.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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-09-07 19:08:51 -04:00
|
|
|
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 {
|
2018-10-09 14:58:26 -04:00
|
|
|
// On client SKUs, default to Hyper-V. @engine maintainers. This
|
2019-09-25 13:51:18 -04:00
|
|
|
// should not be removed. Ping Microsoft folks is there are PRs to
|
2018-10-09 14:58:26 -04:00
|
|
|
// to change this.
|
2022-03-15 19:41:30 -04:00
|
|
|
if operatingsystem.IsWindowsClient() {
|
2022-02-17 12:25:38 -05:00
|
|
|
daemon.defaultIsolation = containertypes.IsolationHyperV
|
|
|
|
} else {
|
|
|
|
daemon.defaultIsolation = containertypes.IsolationProcess
|
2016-04-14 20:12:02 -04:00
|
|
|
}
|
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() {
|
2022-02-17 12:25:38 -05:00
|
|
|
daemon.defaultIsolation = containertypes.IsolationHyperV
|
2016-03-18 14:53:27 -04:00
|
|
|
}
|
2016-04-14 20:12:02 -04:00
|
|
|
if containertypes.Isolation(val).IsProcess() {
|
2022-02-17 12:25:38 -05:00
|
|
|
daemon.defaultIsolation = containertypes.IsolationProcess
|
2016-04-14 20:12:02 -04:00
|
|
|
}
|
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
|
|
|
|
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
|
|
|
|
2016-09-02 09:20:54 -04:00
|
|
|
func (daemon *Daemon) setupSeccompProfile() error {
|
|
|
|
return nil
|
|
|
|
}
|
2017-05-31 20:11:42 -04:00
|
|
|
|
2017-09-22 09:52:41 -04:00
|
|
|
func (daemon *Daemon) loadRuntimes() error {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-02-17 11:57:51 -05:00
|
|
|
func setupResolvConf(config *config.Config) {}
|
2019-11-05 02:10:19 -05:00
|
|
|
|
daemon: load and cache sysInfo on initialization
The `daemon.RawSysInfo()` function can be a heavy operation, as it collects
information about all cgroups on the host, networking, AppArmor, Seccomp, etc.
While looking at our code, I noticed that various parts in the code call this
function, potentially even _multiple times_ per container, for example, it is
called from:
- `verifyPlatformContainerSettings()`
- `oci.WithCgroups()` if the daemon has `cpu-rt-period` or `cpu-rt-runtime` configured
- in `ContainerDecoder.DecodeConfig()`, which is called on boith `container create` and `container commit`
Given that this information is not expected to change during the daemon's
lifecycle, and various information coming from this (such as seccomp and
apparmor status) was already cached, we may as well load it once, and cache
the results in the daemon instance.
This patch updates `daemon.RawSysInfo()` to use a `sync.Once()` so that
it's only executed once for the daemon's lifecycle.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2022-01-07 06:54:47 -05:00
|
|
|
func (daemon *Daemon) loadSysInfo() {
|
|
|
|
daemon.sysInfo = sysinfo.New()
|
2020-03-10 08:09:25 -04:00
|
|
|
}
|
2021-02-26 18:23:55 -05:00
|
|
|
|
|
|
|
func (daemon *Daemon) initLibcontainerd(ctx context.Context) error {
|
|
|
|
var err error
|
|
|
|
|
|
|
|
rt := daemon.configStore.GetDefaultRuntimeName()
|
|
|
|
if rt == "" {
|
|
|
|
if daemon.configStore.ContainerdAddr == "" {
|
|
|
|
rt = windowsV1RuntimeName
|
|
|
|
} else {
|
|
|
|
rt = windowsV2RuntimeName
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
switch rt {
|
|
|
|
case windowsV1RuntimeName:
|
|
|
|
daemon.containerd, err = local.NewClient(
|
|
|
|
ctx,
|
|
|
|
daemon.containerdCli,
|
|
|
|
filepath.Join(daemon.configStore.ExecRoot, "containerd"),
|
|
|
|
daemon.configStore.ContainerdNamespace,
|
|
|
|
daemon,
|
|
|
|
)
|
|
|
|
case windowsV2RuntimeName:
|
|
|
|
if daemon.configStore.ContainerdAddr == "" {
|
|
|
|
return fmt.Errorf("cannot use the specified runtime %q without containerd", rt)
|
|
|
|
}
|
|
|
|
daemon.containerd, err = remote.NewClient(
|
|
|
|
ctx,
|
|
|
|
daemon.containerdCli,
|
|
|
|
filepath.Join(daemon.configStore.ExecRoot, "containerd"),
|
|
|
|
daemon.configStore.ContainerdNamespace,
|
|
|
|
daemon,
|
|
|
|
)
|
|
|
|
default:
|
|
|
|
return fmt.Errorf("unknown windows runtime %s", rt)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
|
|
|
}
|