github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/daemon/daemon_windows.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math"
     7  	"path/filepath"
     8  	"runtime"
     9  	"strings"
    10  
    11  	"github.com/Microsoft/hcsshim"
    12  	"github.com/Microsoft/hcsshim/osversion"
    13  	"github.com/docker/docker/api/types"
    14  	containertypes "github.com/docker/docker/api/types/container"
    15  	"github.com/docker/docker/container"
    16  	"github.com/docker/docker/daemon/config"
    17  	"github.com/docker/docker/libcontainerd/local"
    18  	"github.com/docker/docker/libcontainerd/remote"
    19  	"github.com/docker/docker/libnetwork"
    20  	nwconfig "github.com/docker/docker/libnetwork/config"
    21  	"github.com/docker/docker/libnetwork/datastore"
    22  	winlibnetwork "github.com/docker/docker/libnetwork/drivers/windows"
    23  	"github.com/docker/docker/libnetwork/netlabel"
    24  	"github.com/docker/docker/libnetwork/options"
    25  	"github.com/docker/docker/pkg/containerfs"
    26  	"github.com/docker/docker/pkg/idtools"
    27  	"github.com/docker/docker/pkg/parsers"
    28  	"github.com/docker/docker/pkg/parsers/operatingsystem"
    29  	"github.com/docker/docker/pkg/platform"
    30  	"github.com/docker/docker/pkg/sysinfo"
    31  	"github.com/docker/docker/pkg/system"
    32  	"github.com/docker/docker/runconfig"
    33  	"github.com/pkg/errors"
    34  	"github.com/sirupsen/logrus"
    35  	"golang.org/x/sys/windows"
    36  	"golang.org/x/sys/windows/svc/mgr"
    37  )
    38  
    39  const (
    40  	isWindows            = true
    41  	platformSupported    = true
    42  	windowsMinCPUShares  = 1
    43  	windowsMaxCPUShares  = 10000
    44  	windowsMinCPUPercent = 1
    45  	windowsMaxCPUPercent = 100
    46  
    47  	windowsV1RuntimeName = "com.docker.hcsshim.v1"
    48  	windowsV2RuntimeName = "io.containerd.runhcs.v1"
    49  )
    50  
    51  // Windows containers are much larger than Linux containers and each of them
    52  // have > 20 system processes which why we use much smaller parallelism value.
    53  func adjustParallelLimit(n int, limit int) int {
    54  	return int(math.Max(1, math.Floor(float64(runtime.NumCPU())*.8)))
    55  }
    56  
    57  // Windows has no concept of an execution state directory. So use config.Root here.
    58  func getPluginExecRoot(root string) string {
    59  	return filepath.Join(root, "plugins")
    60  }
    61  
    62  func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
    63  	return nil
    64  }
    65  
    66  func setupInitLayer(idMapping idtools.IdentityMapping) func(containerfs.ContainerFS) error {
    67  	return nil
    68  }
    69  
    70  // adaptContainerSettings is called during container creation to modify any
    71  // settings necessary in the HostConfig structure.
    72  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
    73  	return nil
    74  }
    75  
    76  // verifyPlatformContainerResources performs platform-specific validation of the container's resource-configuration
    77  func verifyPlatformContainerResources(resources *containertypes.Resources, isHyperv bool) (warnings []string, err error) {
    78  	fixMemorySwappiness(resources)
    79  	if !isHyperv {
    80  		// The processor resource controls are mutually exclusive on
    81  		// Windows Server Containers, the order of precedence is
    82  		// CPUCount first, then CPUShares, and CPUPercent last.
    83  		if resources.CPUCount > 0 {
    84  			if resources.CPUShares > 0 {
    85  				warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU shares on Windows Server Containers. CPU shares discarded")
    86  				resources.CPUShares = 0
    87  			}
    88  			if resources.CPUPercent > 0 {
    89  				warnings = append(warnings, "Conflicting options: CPU count takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
    90  				resources.CPUPercent = 0
    91  			}
    92  		} else if resources.CPUShares > 0 {
    93  			if resources.CPUPercent > 0 {
    94  				warnings = append(warnings, "Conflicting options: CPU shares takes priority over CPU percent on Windows Server Containers. CPU percent discarded")
    95  				resources.CPUPercent = 0
    96  			}
    97  		}
    98  	}
    99  
   100  	if resources.CPUShares < 0 || resources.CPUShares > windowsMaxCPUShares {
   101  		return warnings, fmt.Errorf("range of CPUShares is from %d to %d", windowsMinCPUShares, windowsMaxCPUShares)
   102  	}
   103  	if resources.CPUPercent < 0 || resources.CPUPercent > windowsMaxCPUPercent {
   104  		return warnings, fmt.Errorf("range of CPUPercent is from %d to %d", windowsMinCPUPercent, windowsMaxCPUPercent)
   105  	}
   106  	if resources.CPUCount < 0 {
   107  		return warnings, fmt.Errorf("invalid CPUCount: CPUCount cannot be negative")
   108  	}
   109  
   110  	if resources.NanoCPUs > 0 && resources.CPUPercent > 0 {
   111  		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Percent cannot both be set")
   112  	}
   113  	if resources.NanoCPUs > 0 && resources.CPUShares > 0 {
   114  		return warnings, fmt.Errorf("conflicting options: Nano CPUs and CPU Shares cannot both be set")
   115  	}
   116  	// The precision we could get is 0.01, because on Windows we have to convert to CPUPercent.
   117  	// We don't set the lower limit here and it is up to the underlying platform (e.g., Windows) to return an error.
   118  	if resources.NanoCPUs < 0 || resources.NanoCPUs > int64(sysinfo.NumCPU())*1e9 {
   119  		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())
   120  	}
   121  
   122  	if len(resources.BlkioDeviceReadBps) > 0 {
   123  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadBps")
   124  	}
   125  	if len(resources.BlkioDeviceReadIOps) > 0 {
   126  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceReadIOps")
   127  	}
   128  	if len(resources.BlkioDeviceWriteBps) > 0 {
   129  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteBps")
   130  	}
   131  	if len(resources.BlkioDeviceWriteIOps) > 0 {
   132  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioDeviceWriteIOps")
   133  	}
   134  	if resources.BlkioWeight > 0 {
   135  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeight")
   136  	}
   137  	if len(resources.BlkioWeightDevice) > 0 {
   138  		return warnings, fmt.Errorf("invalid option: Windows does not support BlkioWeightDevice")
   139  	}
   140  	if resources.CgroupParent != "" {
   141  		return warnings, fmt.Errorf("invalid option: Windows does not support CgroupParent")
   142  	}
   143  	if resources.CPUPeriod != 0 {
   144  		return warnings, fmt.Errorf("invalid option: Windows does not support CPUPeriod")
   145  	}
   146  	if resources.CpusetCpus != "" {
   147  		return warnings, fmt.Errorf("invalid option: Windows does not support CpusetCpus")
   148  	}
   149  	if resources.CpusetMems != "" {
   150  		return warnings, fmt.Errorf("invalid option: Windows does not support CpusetMems")
   151  	}
   152  	if resources.KernelMemory != 0 {
   153  		return warnings, fmt.Errorf("invalid option: Windows does not support KernelMemory")
   154  	}
   155  	if resources.MemoryReservation != 0 {
   156  		return warnings, fmt.Errorf("invalid option: Windows does not support MemoryReservation")
   157  	}
   158  	if resources.MemorySwap != 0 {
   159  		return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwap")
   160  	}
   161  	if resources.MemorySwappiness != nil {
   162  		return warnings, fmt.Errorf("invalid option: Windows does not support MemorySwappiness")
   163  	}
   164  	if resources.OomKillDisable != nil && *resources.OomKillDisable {
   165  		return warnings, fmt.Errorf("invalid option: Windows does not support OomKillDisable")
   166  	}
   167  	if resources.PidsLimit != nil && *resources.PidsLimit != 0 {
   168  		return warnings, fmt.Errorf("invalid option: Windows does not support PidsLimit")
   169  	}
   170  	if len(resources.Ulimits) != 0 {
   171  		return warnings, fmt.Errorf("invalid option: Windows does not support Ulimits")
   172  	}
   173  	return warnings, nil
   174  }
   175  
   176  // verifyPlatformContainerSettings performs platform-specific validation of the
   177  // hostconfig and config structures.
   178  func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, update bool) (warnings []string, err error) {
   179  	if hostConfig == nil {
   180  		return nil, nil
   181  	}
   182  	return verifyPlatformContainerResources(&hostConfig.Resources, daemon.runAsHyperVContainer(hostConfig))
   183  }
   184  
   185  // verifyDaemonSettings performs validation of daemon config struct
   186  func verifyDaemonSettings(config *config.Config) error {
   187  	return nil
   188  }
   189  
   190  // checkSystem validates platform-specific requirements
   191  func checkSystem() error {
   192  	// Validate the OS version. Note that dockerd.exe must be manifested for this
   193  	// call to return the correct version.
   194  	if osversion.Get().MajorVersion < 10 || osversion.Build() < osversion.RS5 {
   195  		return fmt.Errorf("this version of Windows does not support the docker daemon (Windows build %d or higher is required)", osversion.RS5)
   196  	}
   197  
   198  	vmcompute := windows.NewLazySystemDLL("vmcompute.dll")
   199  	if vmcompute.Load() != nil {
   200  		return fmt.Errorf("failed to load vmcompute.dll, ensure that the Containers feature is installed")
   201  	}
   202  
   203  	// Ensure that the required Host Network Service and vmcompute services
   204  	// are running. Docker will fail in unexpected ways if this is not present.
   205  	var requiredServices = []string{"hns", "vmcompute"}
   206  	if err := ensureServicesInstalled(requiredServices); err != nil {
   207  		return errors.Wrap(err, "a required service is not installed, ensure the Containers feature is installed")
   208  	}
   209  
   210  	return nil
   211  }
   212  
   213  func ensureServicesInstalled(services []string) error {
   214  	m, err := mgr.Connect()
   215  	if err != nil {
   216  		return err
   217  	}
   218  	defer m.Disconnect()
   219  	for _, service := range services {
   220  		s, err := m.OpenService(service)
   221  		if err != nil {
   222  			return errors.Wrapf(err, "failed to open service %s", service)
   223  		}
   224  		s.Close()
   225  	}
   226  	return nil
   227  }
   228  
   229  // configureKernelSecuritySupport configures and validate security support for the kernel
   230  func configureKernelSecuritySupport(config *config.Config, driverName string) error {
   231  	return nil
   232  }
   233  
   234  // configureMaxThreads sets the Go runtime max threads threshold
   235  func configureMaxThreads(config *config.Config) error {
   236  	return nil
   237  }
   238  
   239  func (daemon *Daemon) initNetworkController(activeSandboxes map[string]interface{}) error {
   240  	netOptions, err := daemon.networkOptions(nil, nil)
   241  	if err != nil {
   242  		return err
   243  	}
   244  	daemon.netController, err = libnetwork.New(netOptions...)
   245  	if err != nil {
   246  		return errors.Wrap(err, "error obtaining controller instance")
   247  	}
   248  
   249  	hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
   250  	if err != nil {
   251  		return err
   252  	}
   253  
   254  	// Remove networks not present in HNS
   255  	for _, v := range daemon.netController.Networks() {
   256  		hnsid := v.Info().DriverOptions()[winlibnetwork.HNSID]
   257  		found := false
   258  
   259  		for _, v := range hnsresponse {
   260  			if v.Id == hnsid {
   261  				found = true
   262  				break
   263  			}
   264  		}
   265  
   266  		if !found {
   267  			// non-default nat networks should be re-created if missing from HNS
   268  			if v.Type() == "nat" && v.Name() != "nat" {
   269  				_, _, v4Conf, v6Conf := v.Info().IpamConfig()
   270  				netOption := map[string]string{}
   271  				for k, v := range v.Info().DriverOptions() {
   272  					if k != winlibnetwork.NetworkName && k != winlibnetwork.HNSID {
   273  						netOption[k] = v
   274  					}
   275  				}
   276  				name := v.Name()
   277  				id := v.ID()
   278  
   279  				err = v.Delete()
   280  				if err != nil {
   281  					logrus.Errorf("Error occurred when removing network %v", err)
   282  				}
   283  
   284  				_, err := daemon.netController.NewNetwork("nat", name, id,
   285  					libnetwork.NetworkOptionGeneric(options.Generic{
   286  						netlabel.GenericData: netOption,
   287  					}),
   288  					libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   289  				)
   290  				if err != nil {
   291  					logrus.Errorf("Error occurred when creating network %v", err)
   292  				}
   293  				continue
   294  			}
   295  
   296  			// global networks should not be deleted by local HNS
   297  			if v.Info().Scope() != datastore.GlobalScope {
   298  				err = v.Delete()
   299  				if err != nil {
   300  					logrus.Errorf("Error occurred when removing network %v", err)
   301  				}
   302  			}
   303  		}
   304  	}
   305  
   306  	_, err = daemon.netController.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
   307  	if err != nil {
   308  		return err
   309  	}
   310  
   311  	defaultNetworkExists := false
   312  
   313  	if network, err := daemon.netController.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   314  		hnsid := network.Info().DriverOptions()[winlibnetwork.HNSID]
   315  		for _, v := range hnsresponse {
   316  			if hnsid == v.Id {
   317  				defaultNetworkExists = true
   318  				break
   319  			}
   320  		}
   321  	}
   322  
   323  	// discover and add HNS networks to windows
   324  	// network that exist are removed and added again
   325  	for _, v := range hnsresponse {
   326  		networkTypeNorm := strings.ToLower(v.Type)
   327  		if networkTypeNorm == "private" || networkTypeNorm == "internal" {
   328  			continue // workaround for HNS reporting unsupported networks
   329  		}
   330  		var n libnetwork.Network
   331  		s := func(current libnetwork.Network) bool {
   332  			hnsid := current.Info().DriverOptions()[winlibnetwork.HNSID]
   333  			if hnsid == v.Id {
   334  				n = current
   335  				return true
   336  			}
   337  			return false
   338  		}
   339  
   340  		daemon.netController.WalkNetworks(s)
   341  
   342  		drvOptions := make(map[string]string)
   343  		nid := ""
   344  		if n != nil {
   345  			nid = n.ID()
   346  
   347  			// global networks should not be deleted by local HNS
   348  			if n.Info().Scope() == datastore.GlobalScope {
   349  				continue
   350  			}
   351  			v.Name = n.Name()
   352  			// This will not cause network delete from HNS as the network
   353  			// is not yet populated in the libnetwork windows driver
   354  
   355  			// restore option if it existed before
   356  			drvOptions = n.Info().DriverOptions()
   357  			n.Delete()
   358  		}
   359  		netOption := map[string]string{
   360  			winlibnetwork.NetworkName: v.Name,
   361  			winlibnetwork.HNSID:       v.Id,
   362  		}
   363  
   364  		// add persisted driver options
   365  		for k, v := range drvOptions {
   366  			if k != winlibnetwork.NetworkName && k != winlibnetwork.HNSID {
   367  				netOption[k] = v
   368  			}
   369  		}
   370  
   371  		v4Conf := []*libnetwork.IpamConf{}
   372  		for _, subnet := range v.Subnets {
   373  			ipamV4Conf := libnetwork.IpamConf{}
   374  			ipamV4Conf.PreferredPool = subnet.AddressPrefix
   375  			ipamV4Conf.Gateway = subnet.GatewayAddress
   376  			v4Conf = append(v4Conf, &ipamV4Conf)
   377  		}
   378  
   379  		name := v.Name
   380  
   381  		// If there is no nat network create one from the first NAT network
   382  		// encountered if it doesn't already exist
   383  		if !defaultNetworkExists &&
   384  			runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) &&
   385  			n == nil {
   386  			name = runconfig.DefaultDaemonNetworkMode().NetworkName()
   387  			defaultNetworkExists = true
   388  		}
   389  
   390  		v6Conf := []*libnetwork.IpamConf{}
   391  		_, err := daemon.netController.NewNetwork(strings.ToLower(v.Type), name, nid,
   392  			libnetwork.NetworkOptionGeneric(options.Generic{
   393  				netlabel.GenericData: netOption,
   394  			}),
   395  			libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   396  		)
   397  
   398  		if err != nil {
   399  			logrus.Errorf("Error occurred when creating network %v", err)
   400  		}
   401  	}
   402  
   403  	if !daemon.configStore.DisableBridge {
   404  		// Initialize default driver "bridge"
   405  		if err := initBridgeDriver(daemon.netController, daemon.configStore); err != nil {
   406  			return err
   407  		}
   408  	}
   409  
   410  	return nil
   411  }
   412  
   413  func initBridgeDriver(controller libnetwork.NetworkController, config *config.Config) error {
   414  	if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   415  		return nil
   416  	}
   417  
   418  	netOption := map[string]string{
   419  		winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
   420  	}
   421  
   422  	var ipamOption libnetwork.NetworkOption
   423  	var subnetPrefix string
   424  
   425  	if config.BridgeConfig.FixedCIDR != "" {
   426  		subnetPrefix = config.BridgeConfig.FixedCIDR
   427  	}
   428  
   429  	if subnetPrefix != "" {
   430  		ipamV4Conf := libnetwork.IpamConf{PreferredPool: subnetPrefix}
   431  		v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
   432  		v6Conf := []*libnetwork.IpamConf{}
   433  		ipamOption = libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil)
   434  	}
   435  
   436  	_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
   437  		libnetwork.NetworkOptionGeneric(options.Generic{
   438  			netlabel.GenericData: netOption,
   439  		}),
   440  		ipamOption,
   441  	)
   442  	if err != nil {
   443  		return errors.Wrap(err, "error creating default network")
   444  	}
   445  
   446  	return nil
   447  }
   448  
   449  // registerLinks sets up links between containers and writes the
   450  // configuration out for persistence. As of Windows TP4, links are not supported.
   451  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
   452  	return nil
   453  }
   454  
   455  func (daemon *Daemon) cleanupMountsByID(in string) error {
   456  	return nil
   457  }
   458  
   459  func (daemon *Daemon) cleanupMounts() error {
   460  	return nil
   461  }
   462  
   463  func recursiveUnmount(_ string) error {
   464  	return nil
   465  }
   466  
   467  func setupRemappedRoot(config *config.Config) (idtools.IdentityMapping, error) {
   468  	return idtools.IdentityMapping{}, nil
   469  }
   470  
   471  func setupDaemonRoot(config *config.Config, rootDir string, rootIdentity idtools.Identity) error {
   472  	config.Root = rootDir
   473  	// Create the root directory if it doesn't exists
   474  	if err := system.MkdirAllWithACL(config.Root, 0, system.SddlAdministratorsLocalSystem); err != nil {
   475  		return err
   476  	}
   477  	return nil
   478  }
   479  
   480  // runasHyperVContainer returns true if we are going to run as a Hyper-V container
   481  func (daemon *Daemon) runAsHyperVContainer(hostConfig *containertypes.HostConfig) bool {
   482  	if hostConfig.Isolation.IsDefault() {
   483  		// Container is set to use the default, so take the default from the daemon configuration
   484  		return daemon.defaultIsolation.IsHyperV()
   485  	}
   486  
   487  	// Container is requesting an isolation mode. Honour it.
   488  	return hostConfig.Isolation.IsHyperV()
   489  
   490  }
   491  
   492  // conditionalMountOnStart is a platform specific helper function during the
   493  // container start to call mount.
   494  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
   495  	if daemon.runAsHyperVContainer(container.HostConfig) {
   496  		// We do not mount if a Hyper-V container as it needs to be mounted inside the
   497  		// utility VM, not the host.
   498  		return nil
   499  	}
   500  	return daemon.Mount(container)
   501  }
   502  
   503  // conditionalUnmountOnCleanup is a platform specific helper function called
   504  // during the cleanup of a container to unmount.
   505  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
   506  	if daemon.runAsHyperVContainer(container.HostConfig) {
   507  		// We do not unmount if a Hyper-V container
   508  		return nil
   509  	}
   510  	return daemon.Unmount(container)
   511  }
   512  
   513  func driverOptions(_ *config.Config) nwconfig.Option {
   514  	return nil
   515  }
   516  
   517  func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
   518  	if !c.IsRunning() {
   519  		return nil, errNotRunning(c.ID)
   520  	}
   521  
   522  	// Obtain the stats from HCS via libcontainerd
   523  	stats, err := daemon.containerd.Stats(context.Background(), c.ID)
   524  	if err != nil {
   525  		if strings.Contains(err.Error(), "container not found") {
   526  			return nil, containerNotFound(c.ID)
   527  		}
   528  		return nil, err
   529  	}
   530  
   531  	// Start with an empty structure
   532  	s := &types.StatsJSON{}
   533  	s.Stats.Read = stats.Read
   534  	s.Stats.NumProcs = platform.NumProcs()
   535  
   536  	if stats.HCSStats != nil {
   537  		hcss := stats.HCSStats
   538  		// Populate the CPU/processor statistics
   539  		s.CPUStats = types.CPUStats{
   540  			CPUUsage: types.CPUUsage{
   541  				TotalUsage:        hcss.Processor.TotalRuntime100ns,
   542  				UsageInKernelmode: hcss.Processor.RuntimeKernel100ns,
   543  				UsageInUsermode:   hcss.Processor.RuntimeUser100ns,
   544  			},
   545  		}
   546  
   547  		// Populate the memory statistics
   548  		s.MemoryStats = types.MemoryStats{
   549  			Commit:            hcss.Memory.UsageCommitBytes,
   550  			CommitPeak:        hcss.Memory.UsageCommitPeakBytes,
   551  			PrivateWorkingSet: hcss.Memory.UsagePrivateWorkingSetBytes,
   552  		}
   553  
   554  		// Populate the storage statistics
   555  		s.StorageStats = types.StorageStats{
   556  			ReadCountNormalized:  hcss.Storage.ReadCountNormalized,
   557  			ReadSizeBytes:        hcss.Storage.ReadSizeBytes,
   558  			WriteCountNormalized: hcss.Storage.WriteCountNormalized,
   559  			WriteSizeBytes:       hcss.Storage.WriteSizeBytes,
   560  		}
   561  
   562  		// Populate the network statistics
   563  		s.Networks = make(map[string]types.NetworkStats)
   564  		for _, nstats := range hcss.Network {
   565  			s.Networks[nstats.EndpointId] = types.NetworkStats{
   566  				RxBytes:   nstats.BytesReceived,
   567  				RxPackets: nstats.PacketsReceived,
   568  				RxDropped: nstats.DroppedPacketsIncoming,
   569  				TxBytes:   nstats.BytesSent,
   570  				TxPackets: nstats.PacketsSent,
   571  				TxDropped: nstats.DroppedPacketsOutgoing,
   572  			}
   573  		}
   574  	}
   575  	return s, nil
   576  }
   577  
   578  // setDefaultIsolation determine the default isolation mode for the
   579  // daemon to run in. This is only applicable on Windows
   580  func (daemon *Daemon) setDefaultIsolation() error {
   581  	// On client SKUs, default to Hyper-V. @engine maintainers. This
   582  	// should not be removed. Ping Microsoft folks is there are PRs to
   583  	// to change this.
   584  	if operatingsystem.IsWindowsClient() {
   585  		daemon.defaultIsolation = containertypes.IsolationHyperV
   586  	} else {
   587  		daemon.defaultIsolation = containertypes.IsolationProcess
   588  	}
   589  	for _, option := range daemon.configStore.ExecOptions {
   590  		key, val, err := parsers.ParseKeyValueOpt(option)
   591  		if err != nil {
   592  			return err
   593  		}
   594  		key = strings.ToLower(key)
   595  		switch key {
   596  
   597  		case "isolation":
   598  			if !containertypes.Isolation(val).IsValid() {
   599  				return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val)
   600  			}
   601  			if containertypes.Isolation(val).IsHyperV() {
   602  				daemon.defaultIsolation = containertypes.IsolationHyperV
   603  			}
   604  			if containertypes.Isolation(val).IsProcess() {
   605  				daemon.defaultIsolation = containertypes.IsolationProcess
   606  			}
   607  		default:
   608  			return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
   609  		}
   610  	}
   611  
   612  	logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
   613  	return nil
   614  }
   615  
   616  func setupDaemonProcess(config *config.Config) error {
   617  	return nil
   618  }
   619  
   620  func (daemon *Daemon) setupSeccompProfile() error {
   621  	return nil
   622  }
   623  
   624  func (daemon *Daemon) loadRuntimes() error {
   625  	return nil
   626  }
   627  
   628  func setupResolvConf(config *config.Config) {}
   629  
   630  func getSysInfo(daemon *Daemon) *sysinfo.SysInfo {
   631  	return sysinfo.New()
   632  }
   633  
   634  func (daemon *Daemon) initLibcontainerd(ctx context.Context) error {
   635  	var err error
   636  
   637  	rt := daemon.configStore.GetDefaultRuntimeName()
   638  	if rt == "" {
   639  		if daemon.configStore.ContainerdAddr == "" {
   640  			rt = windowsV1RuntimeName
   641  		} else {
   642  			rt = windowsV2RuntimeName
   643  		}
   644  	}
   645  
   646  	switch rt {
   647  	case windowsV1RuntimeName:
   648  		daemon.containerd, err = local.NewClient(
   649  			ctx,
   650  			daemon.containerdCli,
   651  			filepath.Join(daemon.configStore.ExecRoot, "containerd"),
   652  			daemon.configStore.ContainerdNamespace,
   653  			daemon,
   654  		)
   655  	case windowsV2RuntimeName:
   656  		if daemon.configStore.ContainerdAddr == "" {
   657  			return fmt.Errorf("cannot use the specified runtime %q without containerd", rt)
   658  		}
   659  		daemon.containerd, err = remote.NewClient(
   660  			ctx,
   661  			daemon.containerdCli,
   662  			filepath.Join(daemon.configStore.ExecRoot, "containerd"),
   663  			daemon.configStore.ContainerdNamespace,
   664  			daemon,
   665  		)
   666  	default:
   667  		return fmt.Errorf("unknown windows runtime %s", rt)
   668  	}
   669  
   670  	return err
   671  }