github.com/portworx/docker@v1.12.1/daemon/daemon_windows.go (about)

     1  package daemon
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"runtime"
    10  	"strings"
    11  
    12  	"github.com/Microsoft/hcsshim"
    13  	"github.com/Sirupsen/logrus"
    14  	"github.com/docker/docker/container"
    15  	"github.com/docker/docker/daemon/graphdriver"
    16  	"github.com/docker/docker/daemon/graphdriver/windows" // register the windows graph driver
    17  	"github.com/docker/docker/dockerversion"
    18  	"github.com/docker/docker/image"
    19  	"github.com/docker/docker/layer"
    20  	"github.com/docker/docker/pkg/idtools"
    21  	"github.com/docker/docker/pkg/parsers"
    22  	"github.com/docker/docker/pkg/sysinfo"
    23  	"github.com/docker/docker/pkg/system"
    24  	"github.com/docker/docker/reference"
    25  	"github.com/docker/docker/runconfig"
    26  	"github.com/docker/engine-api/types"
    27  	pblkiodev "github.com/docker/engine-api/types/blkiodev"
    28  	containertypes "github.com/docker/engine-api/types/container"
    29  	"github.com/docker/libnetwork"
    30  	nwconfig "github.com/docker/libnetwork/config"
    31  	winlibnetwork "github.com/docker/libnetwork/drivers/windows"
    32  	"github.com/docker/libnetwork/netlabel"
    33  	"github.com/docker/libnetwork/options"
    34  	blkiodev "github.com/opencontainers/runc/libcontainer/configs"
    35  )
    36  
    37  const (
    38  	defaultNetworkSpace = "172.16.0.0/12"
    39  	platformSupported   = true
    40  	windowsMinCPUShares = 1
    41  	windowsMaxCPUShares = 10000
    42  )
    43  
    44  func getBlkioWeightDevices(config *containertypes.HostConfig) ([]blkiodev.WeightDevice, error) {
    45  	return nil, nil
    46  }
    47  
    48  func parseSecurityOpt(container *container.Container, config *containertypes.HostConfig) error {
    49  	return nil
    50  }
    51  
    52  func getBlkioReadIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    53  	return nil, nil
    54  }
    55  
    56  func getBlkioWriteIOpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    57  	return nil, nil
    58  }
    59  
    60  func getBlkioReadBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    61  	return nil, nil
    62  }
    63  
    64  func getBlkioWriteBpsDevices(config *containertypes.HostConfig) ([]blkiodev.ThrottleDevice, error) {
    65  	return nil, nil
    66  }
    67  
    68  func setupInitLayer(initLayer string, rootUID, rootGID int) error {
    69  	return nil
    70  }
    71  
    72  func checkKernel() error {
    73  	return nil
    74  }
    75  
    76  func (daemon *Daemon) getCgroupDriver() string {
    77  	return ""
    78  }
    79  
    80  // adaptContainerSettings is called during container creation to modify any
    81  // settings necessary in the HostConfig structure.
    82  func (daemon *Daemon) adaptContainerSettings(hostConfig *containertypes.HostConfig, adjustCPUShares bool) error {
    83  	if hostConfig == nil {
    84  		return nil
    85  	}
    86  
    87  	if hostConfig.CPUShares < 0 {
    88  		logrus.Warnf("Changing requested CPUShares of %d to minimum allowed of %d", hostConfig.CPUShares, windowsMinCPUShares)
    89  		hostConfig.CPUShares = windowsMinCPUShares
    90  	} else if hostConfig.CPUShares > windowsMaxCPUShares {
    91  		logrus.Warnf("Changing requested CPUShares of %d to maximum allowed of %d", hostConfig.CPUShares, windowsMaxCPUShares)
    92  		hostConfig.CPUShares = windowsMaxCPUShares
    93  	}
    94  
    95  	return nil
    96  }
    97  
    98  func verifyContainerResources(resources *containertypes.Resources, sysInfo *sysinfo.SysInfo) ([]string, error) {
    99  	warnings := []string{}
   100  
   101  	// cpu subsystem checks and adjustments
   102  	if resources.CPUPercent < 0 || resources.CPUPercent > 100 {
   103  		return warnings, fmt.Errorf("Range of CPU percent is from 1 to 100")
   104  	}
   105  
   106  	if resources.CPUPercent > 0 && resources.CPUShares > 0 {
   107  		return warnings, fmt.Errorf("Conflicting options: CPU Shares and CPU Percent cannot both be set")
   108  	}
   109  
   110  	// TODO Windows: Add more validation of resource settings not supported on Windows
   111  
   112  	if resources.BlkioWeight > 0 {
   113  		warnings = append(warnings, "Windows does not support Block I/O weight. Weight discarded.")
   114  		logrus.Warn("Windows does not support Block I/O weight. --blkio-weight discarded.")
   115  		resources.BlkioWeight = 0
   116  	}
   117  	if len(resources.BlkioWeightDevice) > 0 {
   118  		warnings = append(warnings, "Windows does not support Block I/O weight_device.")
   119  		logrus.Warn("Windows does not support Block I/O weight_device. --blkio-weight-device discarded.")
   120  		resources.BlkioWeightDevice = []*pblkiodev.WeightDevice{}
   121  	}
   122  	if len(resources.BlkioDeviceReadBps) > 0 {
   123  		warnings = append(warnings, "Windows does not support Block read limit in bytes per second.")
   124  		logrus.Warn("Windows does not support Block I/O read limit in bytes per second. --device-read-bps discarded.")
   125  		resources.BlkioDeviceReadBps = []*pblkiodev.ThrottleDevice{}
   126  	}
   127  	if len(resources.BlkioDeviceWriteBps) > 0 {
   128  		warnings = append(warnings, "Windows does not support Block write limit in bytes per second.")
   129  		logrus.Warn("Windows does not support Block I/O write limit in bytes per second. --device-write-bps discarded.")
   130  		resources.BlkioDeviceWriteBps = []*pblkiodev.ThrottleDevice{}
   131  	}
   132  	if len(resources.BlkioDeviceReadIOps) > 0 {
   133  		warnings = append(warnings, "Windows does not support Block read limit in IO per second.")
   134  		logrus.Warn("Windows does not support Block I/O read limit in IO per second. -device-read-iops discarded.")
   135  		resources.BlkioDeviceReadIOps = []*pblkiodev.ThrottleDevice{}
   136  	}
   137  	if len(resources.BlkioDeviceWriteIOps) > 0 {
   138  		warnings = append(warnings, "Windows does not support Block write limit in IO per second.")
   139  		logrus.Warn("Windows does not support Block I/O write limit in IO per second. --device-write-iops discarded.")
   140  		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
   141  	}
   142  	return warnings, nil
   143  }
   144  
   145  // verifyPlatformContainerSettings performs platform-specific validation of the
   146  // hostconfig and config structures.
   147  func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config, update bool) ([]string, error) {
   148  	warnings := []string{}
   149  
   150  	w, err := verifyContainerResources(&hostConfig.Resources, nil)
   151  	warnings = append(warnings, w...)
   152  	if err != nil {
   153  		return warnings, err
   154  	}
   155  
   156  	return warnings, nil
   157  }
   158  
   159  // platformReload update configuration with platform specific options
   160  func (daemon *Daemon) platformReload(config *Config, attributes *map[string]string) {
   161  }
   162  
   163  // verifyDaemonSettings performs validation of daemon config struct
   164  func verifyDaemonSettings(config *Config) error {
   165  	return nil
   166  }
   167  
   168  // checkSystem validates platform-specific requirements
   169  func checkSystem() error {
   170  	// Validate the OS version. Note that docker.exe must be manifested for this
   171  	// call to return the correct version.
   172  	osv := system.GetOSVersion()
   173  	if osv.MajorVersion < 10 {
   174  		return fmt.Errorf("This version of Windows does not support the docker daemon")
   175  	}
   176  	if osv.Build < 14300 {
   177  		return fmt.Errorf("The Windows daemon requires Windows Server 2016 Technical Preview 5 build 14300 or later")
   178  	}
   179  	return nil
   180  }
   181  
   182  // configureKernelSecuritySupport configures and validate security support for the kernel
   183  func configureKernelSecuritySupport(config *Config, driverName string) error {
   184  	return nil
   185  }
   186  
   187  // configureMaxThreads sets the Go runtime max threads threshold
   188  func configureMaxThreads(config *Config) error {
   189  	return nil
   190  }
   191  
   192  func (daemon *Daemon) initNetworkController(config *Config, activeSandboxes map[string]interface{}) (libnetwork.NetworkController, error) {
   193  	netOptions, err := daemon.networkOptions(config, nil)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	controller, err := libnetwork.New(netOptions...)
   198  	if err != nil {
   199  		return nil, fmt.Errorf("error obtaining controller instance: %v", err)
   200  	}
   201  
   202  	hnsresponse, err := hcsshim.HNSListNetworkRequest("GET", "", "")
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  
   207  	// Remove networks not present in HNS
   208  	for _, v := range controller.Networks() {
   209  		options := v.Info().DriverOptions()
   210  		hnsid := options[winlibnetwork.HNSID]
   211  		found := false
   212  
   213  		for _, v := range hnsresponse {
   214  			if v.Id == hnsid {
   215  				found = true
   216  				break
   217  			}
   218  		}
   219  
   220  		if !found {
   221  			err = v.Delete()
   222  			if err != nil {
   223  				return nil, err
   224  			}
   225  		}
   226  	}
   227  
   228  	_, err = controller.NewNetwork("null", "none", "", libnetwork.NetworkOptionPersist(false))
   229  	if err != nil {
   230  		return nil, err
   231  	}
   232  
   233  	// discover and add HNS networks to windows
   234  	// network that exist are removed and added again
   235  	for _, v := range hnsresponse {
   236  		var n libnetwork.Network
   237  		s := func(current libnetwork.Network) bool {
   238  			options := current.Info().DriverOptions()
   239  			if options[winlibnetwork.HNSID] == v.Id {
   240  				n = current
   241  				return true
   242  			}
   243  			return false
   244  		}
   245  
   246  		controller.WalkNetworks(s)
   247  		if n != nil {
   248  			v.Name = n.Name()
   249  			n.Delete()
   250  		}
   251  
   252  		netOption := map[string]string{
   253  			winlibnetwork.NetworkName: v.Name,
   254  			winlibnetwork.HNSID:       v.Id,
   255  		}
   256  
   257  		v4Conf := []*libnetwork.IpamConf{}
   258  		for _, subnet := range v.Subnets {
   259  			ipamV4Conf := libnetwork.IpamConf{}
   260  			ipamV4Conf.PreferredPool = subnet.AddressPrefix
   261  			ipamV4Conf.Gateway = subnet.GatewayAddress
   262  			v4Conf = append(v4Conf, &ipamV4Conf)
   263  		}
   264  
   265  		name := v.Name
   266  		// There is only one nat network supported in windows.
   267  		// If it exists with a different name add it as the default name
   268  		if runconfig.DefaultDaemonNetworkMode() == containertypes.NetworkMode(strings.ToLower(v.Type)) {
   269  			name = runconfig.DefaultDaemonNetworkMode().NetworkName()
   270  		}
   271  
   272  		v6Conf := []*libnetwork.IpamConf{}
   273  		_, err := controller.NewNetwork(strings.ToLower(v.Type), name, "",
   274  			libnetwork.NetworkOptionGeneric(options.Generic{
   275  				netlabel.GenericData: netOption,
   276  			}),
   277  			libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   278  		)
   279  
   280  		if err != nil {
   281  			logrus.Errorf("Error occurred when creating network %v", err)
   282  		}
   283  	}
   284  
   285  	if !config.DisableBridge {
   286  		// Initialize default driver "bridge"
   287  		if err := initBridgeDriver(controller, config); err != nil {
   288  			return nil, err
   289  		}
   290  	}
   291  
   292  	return controller, nil
   293  }
   294  
   295  func initBridgeDriver(controller libnetwork.NetworkController, config *Config) error {
   296  	if _, err := controller.NetworkByName(runconfig.DefaultDaemonNetworkMode().NetworkName()); err == nil {
   297  		return nil
   298  	}
   299  
   300  	netOption := map[string]string{
   301  		winlibnetwork.NetworkName: runconfig.DefaultDaemonNetworkMode().NetworkName(),
   302  	}
   303  
   304  	ipamV4Conf := libnetwork.IpamConf{}
   305  	if config.bridgeConfig.FixedCIDR == "" {
   306  		ipamV4Conf.PreferredPool = defaultNetworkSpace
   307  	} else {
   308  		ipamV4Conf.PreferredPool = config.bridgeConfig.FixedCIDR
   309  	}
   310  
   311  	v4Conf := []*libnetwork.IpamConf{&ipamV4Conf}
   312  	v6Conf := []*libnetwork.IpamConf{}
   313  
   314  	_, err := controller.NewNetwork(string(runconfig.DefaultDaemonNetworkMode()), runconfig.DefaultDaemonNetworkMode().NetworkName(), "",
   315  		libnetwork.NetworkOptionGeneric(options.Generic{
   316  			netlabel.GenericData: netOption,
   317  		}),
   318  		libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
   319  	)
   320  
   321  	if err != nil {
   322  		return fmt.Errorf("Error creating default network: %v", err)
   323  	}
   324  	return nil
   325  }
   326  
   327  // registerLinks sets up links between containers and writes the
   328  // configuration out for persistence. As of Windows TP4, links are not supported.
   329  func (daemon *Daemon) registerLinks(container *container.Container, hostConfig *containertypes.HostConfig) error {
   330  	return nil
   331  }
   332  
   333  func (daemon *Daemon) cleanupMountsByID(in string) error {
   334  	return nil
   335  }
   336  
   337  func (daemon *Daemon) cleanupMounts() error {
   338  	return nil
   339  }
   340  
   341  func setupRemappedRoot(config *Config) ([]idtools.IDMap, []idtools.IDMap, error) {
   342  	return nil, nil, nil
   343  }
   344  
   345  func setupDaemonRoot(config *Config, rootDir string, rootUID, rootGID int) error {
   346  	config.Root = rootDir
   347  	// Create the root directory if it doesn't exists
   348  	if err := system.MkdirAll(config.Root, 0700); err != nil && !os.IsExist(err) {
   349  		return err
   350  	}
   351  	return nil
   352  }
   353  
   354  // runasHyperVContainer returns true if we are going to run as a Hyper-V container
   355  func (daemon *Daemon) runAsHyperVContainer(container *container.Container) bool {
   356  	if container.HostConfig.Isolation.IsDefault() {
   357  		// Container is set to use the default, so take the default from the daemon configuration
   358  		return daemon.defaultIsolation.IsHyperV()
   359  	}
   360  
   361  	// Container is requesting an isolation mode. Honour it.
   362  	return container.HostConfig.Isolation.IsHyperV()
   363  
   364  }
   365  
   366  // conditionalMountOnStart is a platform specific helper function during the
   367  // container start to call mount.
   368  func (daemon *Daemon) conditionalMountOnStart(container *container.Container) error {
   369  	// We do not mount if a Hyper-V container
   370  	if !daemon.runAsHyperVContainer(container) {
   371  		return daemon.Mount(container)
   372  	}
   373  	return nil
   374  }
   375  
   376  // conditionalUnmountOnCleanup is a platform specific helper function called
   377  // during the cleanup of a container to unmount.
   378  func (daemon *Daemon) conditionalUnmountOnCleanup(container *container.Container) error {
   379  	// We do not unmount if a Hyper-V container
   380  	if !daemon.runAsHyperVContainer(container) {
   381  		return daemon.Unmount(container)
   382  	}
   383  	return nil
   384  }
   385  
   386  func restoreCustomImage(is image.Store, ls layer.Store, rs reference.Store) error {
   387  	type graphDriverStore interface {
   388  		GraphDriver() graphdriver.Driver
   389  	}
   390  
   391  	gds, ok := ls.(graphDriverStore)
   392  	if !ok {
   393  		return nil
   394  	}
   395  
   396  	driver := gds.GraphDriver()
   397  	wd, ok := driver.(*windows.Driver)
   398  	if !ok {
   399  		return nil
   400  	}
   401  
   402  	imageInfos, err := wd.GetCustomImageInfos()
   403  	if err != nil {
   404  		return err
   405  	}
   406  
   407  	// Convert imageData to valid image configuration
   408  	for _, info := range imageInfos {
   409  		name := strings.ToLower(info.Name)
   410  
   411  		type registrar interface {
   412  			RegisterDiffID(graphID string, size int64) (layer.Layer, error)
   413  		}
   414  		r, ok := ls.(registrar)
   415  		if !ok {
   416  			return errors.New("Layerstore doesn't support RegisterDiffID")
   417  		}
   418  		if _, err := r.RegisterDiffID(info.ID, info.Size); err != nil {
   419  			return err
   420  		}
   421  		// layer is intentionally not released
   422  
   423  		rootFS := image.NewRootFSWithBaseLayer(filepath.Base(info.Path))
   424  
   425  		// Create history for base layer
   426  		config, err := json.Marshal(&image.Image{
   427  			V1Image: image.V1Image{
   428  				DockerVersion: dockerversion.Version,
   429  				Architecture:  runtime.GOARCH,
   430  				OS:            runtime.GOOS,
   431  				Created:       info.CreatedTime,
   432  			},
   433  			RootFS:     rootFS,
   434  			History:    []image.History{},
   435  			OSVersion:  info.OSVersion,
   436  			OSFeatures: info.OSFeatures,
   437  		})
   438  
   439  		named, err := reference.ParseNamed(name)
   440  		if err != nil {
   441  			return err
   442  		}
   443  
   444  		ref, err := reference.WithTag(named, info.Version)
   445  		if err != nil {
   446  			return err
   447  		}
   448  
   449  		id, err := is.Create(config)
   450  		if err != nil {
   451  			logrus.Warnf("Failed to restore custom image %s with error: %s.", name, err)
   452  			logrus.Warnf("Skipping image %s...", name)
   453  			continue
   454  		}
   455  
   456  		if err := rs.AddTag(ref, id, true); err != nil {
   457  			return err
   458  		}
   459  
   460  		logrus.Debugf("Registered base layer %s as %s", ref, id)
   461  	}
   462  	return nil
   463  }
   464  
   465  func driverOptions(config *Config) []nwconfig.Option {
   466  	return []nwconfig.Option{}
   467  }
   468  
   469  func (daemon *Daemon) stats(c *container.Container) (*types.StatsJSON, error) {
   470  	return nil, nil
   471  }
   472  
   473  // setDefaultIsolation determine the default isolation mode for the
   474  // daemon to run in. This is only applicable on Windows
   475  func (daemon *Daemon) setDefaultIsolation() error {
   476  	daemon.defaultIsolation = containertypes.Isolation("process")
   477  	// On client SKUs, default to Hyper-V
   478  	if system.IsWindowsClient() {
   479  		daemon.defaultIsolation = containertypes.Isolation("hyperv")
   480  	}
   481  	for _, option := range daemon.configStore.ExecOptions {
   482  		key, val, err := parsers.ParseKeyValueOpt(option)
   483  		if err != nil {
   484  			return err
   485  		}
   486  		key = strings.ToLower(key)
   487  		switch key {
   488  
   489  		case "isolation":
   490  			if !containertypes.Isolation(val).IsValid() {
   491  				return fmt.Errorf("Invalid exec-opt value for 'isolation':'%s'", val)
   492  			}
   493  			if containertypes.Isolation(val).IsHyperV() {
   494  				daemon.defaultIsolation = containertypes.Isolation("hyperv")
   495  			}
   496  			if containertypes.Isolation(val).IsProcess() {
   497  				if system.IsWindowsClient() {
   498  					return fmt.Errorf("Windows client operating systems only support Hyper-V containers")
   499  				}
   500  				daemon.defaultIsolation = containertypes.Isolation("process")
   501  			}
   502  		default:
   503  			return fmt.Errorf("Unrecognised exec-opt '%s'\n", key)
   504  		}
   505  	}
   506  
   507  	logrus.Infof("Windows default isolation mode: %s", daemon.defaultIsolation)
   508  	return nil
   509  }
   510  
   511  func rootFSToAPIType(rootfs *image.RootFS) types.RootFS {
   512  	var layers []string
   513  	for _, l := range rootfs.DiffIDs {
   514  		layers = append(layers, l.String())
   515  	}
   516  	return types.RootFS{
   517  		Type:      rootfs.Type,
   518  		Layers:    layers,
   519  		BaseLayer: rootfs.BaseLayer,
   520  	}
   521  }
   522  
   523  func setupDaemonProcess(config *Config) error {
   524  	return nil
   525  }