2015-05-15 19:34:26 -04:00
package daemon
import (
2017-09-22 09:52:41 -04:00
"context"
2015-05-15 19:34:26 -04:00
"fmt"
2017-02-02 14:22:12 -05:00
"path/filepath"
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"
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"
2017-08-03 20:22:00 -04:00
"github.com/docker/docker/pkg/containerfs"
2017-05-31 20:11:42 -04:00
"github.com/docker/docker/pkg/fileutils"
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"
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 (
2016-11-01 16:02:46 -04:00
defaultNetworkSpace = "172.16.0.0/12"
platformSupported = true
windowsMinCPUShares = 1
windowsMaxCPUShares = 10000
windowsMinCPUPercent = 1
windowsMaxCPUPercent = 100
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
}
2017-08-03 20:22:00 -04:00
func ( daemon * Daemon ) getLayerInit ( ) func ( containerfs . ContainerFS ) error {
2016-09-21 14:45:25 -04:00
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 { }
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" )
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
}
2017-04-12 19:54:27 -04:00
osv := system . GetOSVersion ( )
if resources . NanoCPUs > 0 && isHyperv && osv . Build < 16175 {
leftoverNanoCPUs := resources . NanoCPUs % 1e9
if leftoverNanoCPUs != 0 && resources . NanoCPUs > 1e9 {
resources . NanoCPUs = ( ( resources . NanoCPUs + 1e9 / 2 ) / 1e9 ) * 1e9
warningString := fmt . Sprintf ( "Your current OS version does not support Hyper-V containers with NanoCPUs greater than 1000000000 but not divisible by 1000000000. NanoCPUs rounded to %d" , resources . NanoCPUs )
warnings = append ( warnings , warningString )
logrus . Warn ( warningString )
}
}
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" )
}
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 )
2017-05-25 20:52:01 -04:00
if ! hyperv && system . IsWindowsClient ( ) && ! system . IsIoTCore ( ) {
2016-11-10 17:35:19 -05: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.
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
Implement none, private, and shareable ipc modes
Since the commit d88fe447df0e8 ("Add support for sharing /dev/shm/ and
/dev/mqueue between containers") container's /dev/shm is mounted on the
host first, then bind-mounted inside the container. This is done that
way in order to be able to share this container's IPC namespace
(and the /dev/shm mount point) with another container.
Unfortunately, this functionality breaks container checkpoint/restore
(even if IPC is not shared). Since /dev/shm is an external mount, its
contents is not saved by `criu checkpoint`, and so upon restore any
application that tries to access data under /dev/shm is severily
disappointed (which usually results in a fatal crash).
This commit solves the issue by introducing new IPC modes for containers
(in addition to 'host' and 'container:ID'). The new modes are:
- 'shareable': enables sharing this container's IPC with others
(this used to be the implicit default);
- 'private': disables sharing this container's IPC.
In 'private' mode, container's /dev/shm is truly mounted inside the
container, without any bind-mounting from the host, which solves the
issue.
While at it, let's also implement 'none' mode. The motivation, as
eloquently put by Justin Cormack, is:
> I wondered a while back about having a none shm mode, as currently it is
> not possible to have a totally unwriteable container as there is always
> a /dev/shm writeable mount. It is a bit of a niche case (and clearly
> should never be allowed to be daemon default) but it would be trivial to
> add now so maybe we should...
...so here's yet yet another mode:
- 'none': no /dev/shm mount inside the container (though it still
has its own private IPC namespace).
Now, to ultimately solve the abovementioned checkpoint/restore issue, we'd
need to make 'private' the default mode, but unfortunately it breaks the
backward compatibility. So, let's make the default container IPC mode
per-daemon configurable (with the built-in default set to 'shareable'
for now). The default can be changed either via a daemon CLI option
(--default-shm-mode) or a daemon.json configuration file parameter
of the same name.
Note one can only set either 'shareable' or 'private' IPC modes as a
daemon default (i.e. in this context 'host', 'container', or 'none'
do not make much sense).
Some other changes this patch introduces are:
1. A mount for /dev/shm is added to default OCI Linux spec.
2. IpcMode.Valid() is simplified to remove duplicated code that parsed
'container:ID' form. Note the old version used to check that ID does
not contain a semicolon -- this is no longer the case (tests are
modified accordingly). The motivation is we should either do a
proper check for container ID validity, or don't check it at all
(since it is checked in other places anyway). I chose the latter.
3. IpcMode.Container() is modified to not return container ID if the
mode value does not start with "container:", unifying the check to
be the same as in IpcMode.IsContainer().
3. IPC mode unit tests (runconfig/hostconfig_test.go) are modified
to add checks for newly added values.
[v2: addressed review at https://github.com/moby/moby/pull/34087#pullrequestreview-51345997]
[v3: addressed review at https://github.com/moby/moby/pull/34087#pullrequestreview-53902833]
[v4: addressed the case of upgrading from older daemon, in this case
container.HostConfig.IpcMode is unset and this is valid]
[v5: document old and new IpcMode values in api/swagger.yaml]
[v6: add the 'none' mode, changelog entry to docs/api/version-history.md]
Signed-off-by: Kir Kolyshkin <kolyshkin@gmail.com>
2017-06-27 17:58:50 -04:00
func ( daemon * Daemon ) reloadPlatform ( config * config . Config , attributes map [ string ] string ) error {
return nil
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 {
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-05-16 19:56:56 -04:00
func configureKernelSecuritySupport ( config * config . Config , driverNames [ ] 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 {
2017-05-05 12:03:22 -04:00
if strings . ToLower ( v . Type ) == "private" {
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 {
options := current . Info ( ) . DriverOptions ( )
if options [ winlibnetwork . HNSID ] == v . Id {
n = current
return true
}
return false
}
controller . WalkNetworks ( s )
2017-11-21 15:00:26 -05:00
drvOptions := make ( map [ string ] string )
2016-03-09 23:33:21 -05:00
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
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 { }
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-05-19 18:06:46 -04:00
func setupRemappedRoot ( config * config . Config ) ( * idtools . IDMappings , error ) {
return & idtools . IDMappings { } , nil
2016-01-07 22:43:11 -05:00
}
2017-05-19 18:06:46 -04:00
func setupDaemonRoot ( config * config . Config , rootDir string , rootIDs idtools . IDPair ) 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 {
2017-08-08 15:43:48 -04:00
// Bail out now for Linux containers. We cannot mount the containers filesystem on the
// host as it is a non-Windows filesystem.
if system . LCOWSupported ( ) && container . OS != "windows" {
2017-06-16 23:28:18 -04:00
return nil
}
2017-08-08 15:43:48 -04:00
// We do not mount if a Hyper-V container as it needs to be mounted inside the
// utility VM, not the host.
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 {
2017-06-16 23:28:18 -04:00
// Bail out now for Linux containers
2017-08-08 15:43:48 -04:00
if system . LCOWSupported ( ) && container . OS != "windows" {
2017-06-16 23:28:18 -04:00
return nil
}
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 ( ) {
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 ,
UsageInUsermode : hcss . Processor . RuntimeKernel100ns ,
} ,
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 {
daemon . defaultIsolation = containertypes . Isolation ( "process" )
2017-05-25 20:52:01 -04:00
// On client SKUs, default to Hyper-V. Note that IoT reports as a client SKU
// but it should not be treated as such.
if system . IsWindowsClient ( ) && ! system . IsIoTCore ( ) {
2016-04-14 20:12:02 -04:00
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 ( ) {
2017-05-25 20:52:01 -04:00
if system . IsWindowsClient ( ) && ! system . IsIoTCore ( ) {
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-05-31 20:11:42 -04:00
func getRealPath ( path string ) ( string , error ) {
if system . IsIoTCore ( ) {
// Due to https://github.com/golang/go/issues/20506, path expansion
// does not work correctly on the default IoT Core configuration.
// TODO @darrenstahlmsft remove this once golang/go/20506 is fixed
return path , nil
}
return fileutils . ReadSymlinkedDirectory ( path )
}
2017-09-22 09:52:41 -04:00
func ( daemon * Daemon ) loadRuntimes ( ) error {
return nil
}
func ( daemon * Daemon ) initRuntimes ( _ map [ string ] types . Runtime ) error {
return nil
}