2015-07-30 21:01:53 +00:00
// Package daemon exposes the functions that occur on the host server
// that the Docker daemon is running.
//
// In implementing the various functions of the daemon, there is often
// a method-specific struct for configuring the runtime behavior.
2014-04-17 21:43:01 +00:00
package daemon
2013-01-19 00:13:39 +00:00
import (
2017-03-30 20:52:40 +00:00
"context"
2013-01-19 00:13:39 +00:00
"fmt"
2014-04-28 21:36:04 +00:00
"io/ioutil"
2015-12-17 17:35:24 +00:00
"net"
2014-04-28 21:36:04 +00:00
"os"
2015-09-04 00:51:04 +00:00
"path"
2015-01-16 19:48:25 +00:00
"path/filepath"
2014-07-30 06:51:43 +00:00
"runtime"
Remove static errors from errors package.
Moving all strings to the errors package wasn't a good idea after all.
Our custom implementation of Go errors predates everything that's nice
and good about working with errors in Go. Take as an example what we
have to do to get an error message:
```go
func GetErrorMessage(err error) string {
switch err.(type) {
case errcode.Error:
e, _ := err.(errcode.Error)
return e.Message
case errcode.ErrorCode:
ec, _ := err.(errcode.ErrorCode)
return ec.Message()
default:
return err.Error()
}
}
```
This goes against every good practice for Go development. The language already provides a simple, intuitive and standard way to get error messages, that is calling the `Error()` method from an error. Reinventing the error interface is a mistake.
Our custom implementation also makes very hard to reason about errors, another nice thing about Go. I found several (>10) error declarations that we don't use anywhere. This is a clear sign about how little we know about the errors we return. I also found several error usages where the number of arguments was different than the parameters declared in the error, another clear example of how difficult is to reason about errors.
Moreover, our custom implementation didn't really make easier for people to return custom HTTP status code depending on the errors. Again, it's hard to reason about when to set custom codes and how. Take an example what we have to do to extract the message and status code from an error before returning a response from the API:
```go
switch err.(type) {
case errcode.ErrorCode:
daError, _ := err.(errcode.ErrorCode)
statusCode = daError.Descriptor().HTTPStatusCode
errMsg = daError.Message()
case errcode.Error:
// For reference, if you're looking for a particular error
// then you can do something like :
// import ( derr "github.com/docker/docker/errors" )
// if daError.ErrorCode() == derr.ErrorCodeNoSuchContainer { ... }
daError, _ := err.(errcode.Error)
statusCode = daError.ErrorCode().Descriptor().HTTPStatusCode
errMsg = daError.Message
default:
// This part of will be removed once we've
// converted everything over to use the errcode package
// FIXME: this is brittle and should not be necessary.
// If we need to differentiate between different possible error types,
// we should create appropriate error types with clearly defined meaning
errStr := strings.ToLower(err.Error())
for keyword, status := range map[string]int{
"not found": http.StatusNotFound,
"no such": http.StatusNotFound,
"bad parameter": http.StatusBadRequest,
"conflict": http.StatusConflict,
"impossible": http.StatusNotAcceptable,
"wrong login/password": http.StatusUnauthorized,
"hasn't been activated": http.StatusForbidden,
} {
if strings.Contains(errStr, keyword) {
statusCode = status
break
}
}
}
```
You can notice two things in that code:
1. We have to explain how errors work, because our implementation goes against how easy to use Go errors are.
2. At no moment we arrived to remove that `switch` statement that was the original reason to use our custom implementation.
This change removes all our status errors from the errors package and puts them back in their specific contexts.
IT puts the messages back with their contexts. That way, we know right away when errors used and how to generate their messages.
It uses custom interfaces to reason about errors. Errors that need to response with a custom status code MUST implementent this simple interface:
```go
type errorWithStatus interface {
HTTPErrorStatusCode() int
}
```
This interface is very straightforward to implement. It also preserves Go errors real behavior, getting the message is as simple as using the `Error()` method.
I included helper functions to generate errors that use custom status code in `errors/errors.go`.
By doing this, we remove the hard dependency we have eeverywhere to our custom errors package. Yes, you can use it as a helper to generate error, but it's still very easy to generate errors without it.
Please, read this fantastic blog post about errors in Go: http://dave.cheney.net/2014/12/24/inspecting-errors
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-25 15:53:35 +00:00
"strings"
2014-04-28 21:36:04 +00:00
"sync"
"time"
2015-03-26 22:22:04 +00:00
"github.com/Sirupsen/logrus"
2017-05-09 14:39:23 +00:00
containerd "github.com/containerd/containerd/api/grpc/types"
2014-11-17 19:23:41 +00:00
"github.com/docker/docker/api"
2016-09-06 18:18:12 +00:00
"github.com/docker/docker/api/types"
containertypes "github.com/docker/docker/api/types/container"
2015-11-12 19:55:17 +00:00
"github.com/docker/docker/container"
2017-01-23 11:23:07 +00:00
"github.com/docker/docker/daemon/config"
"github.com/docker/docker/daemon/discovery"
2015-04-03 22:17:49 +00:00
"github.com/docker/docker/daemon/events"
2015-11-20 22:35:16 +00:00
"github.com/docker/docker/daemon/exec"
2016-11-14 18:53:53 +00:00
"github.com/docker/docker/daemon/logger"
2015-12-23 18:43:34 +00:00
// register graph drivers
_ "github.com/docker/docker/daemon/graphdriver/register"
2017-01-04 17:01:59 +00:00
"github.com/docker/docker/daemon/initlayer"
"github.com/docker/docker/daemon/stats"
2015-11-18 22:20:54 +00:00
dmetadata "github.com/docker/docker/distribution/metadata"
2015-11-14 00:59:01 +00:00
"github.com/docker/docker/distribution/xfer"
2017-01-04 17:01:59 +00:00
"github.com/docker/docker/dockerversion"
2015-07-20 17:57:15 +00:00
"github.com/docker/docker/image"
2015-11-18 22:20:54 +00:00
"github.com/docker/docker/layer"
2016-03-18 18:50:19 +00:00
"github.com/docker/docker/libcontainerd"
2015-11-18 22:20:54 +00:00
"github.com/docker/docker/migrate/v1"
2015-10-08 15:51:41 +00:00
"github.com/docker/docker/pkg/idtools"
2016-10-07 20:53:14 +00:00
"github.com/docker/docker/pkg/plugingetter"
2015-09-04 00:51:04 +00:00
"github.com/docker/docker/pkg/registrar"
2015-08-25 01:42:58 +00:00
"github.com/docker/docker/pkg/signal"
2014-07-24 22:19:50 +00:00
"github.com/docker/docker/pkg/sysinfo"
2015-05-15 23:34:26 +00:00
"github.com/docker/docker/pkg/system"
2014-07-24 22:19:50 +00:00
"github.com/docker/docker/pkg/truncindex"
2017-01-04 17:01:59 +00:00
"github.com/docker/docker/plugin"
2017-01-26 00:54:18 +00:00
refstore "github.com/docker/docker/reference"
2015-03-31 23:21:37 +00:00
"github.com/docker/docker/registry"
2014-07-24 22:19:50 +00:00
"github.com/docker/docker/runconfig"
2015-09-16 21:18:24 +00:00
volumedrivers "github.com/docker/docker/volume/drivers"
"github.com/docker/docker/volume/local"
2015-09-18 23:58:05 +00:00
"github.com/docker/docker/volume/store"
2015-05-15 23:34:26 +00:00
"github.com/docker/libnetwork"
2017-01-04 17:01:59 +00:00
"github.com/docker/libnetwork/cluster"
2016-03-10 04:33:21 +00:00
nwconfig "github.com/docker/libnetwork/config"
2015-11-18 22:20:54 +00:00
"github.com/docker/libtrust"
2016-12-12 23:05:53 +00:00
"github.com/pkg/errors"
2015-11-14 00:59:01 +00:00
)
2013-12-12 21:34:26 +00:00
var (
2016-05-23 21:49:50 +00:00
// DefaultRuntimeBinary is the default runtime to be used by
// containerd if none is specified
DefaultRuntimeBinary = "docker-runc"
2016-12-25 06:37:31 +00:00
errSystemNotSupported = errors . New ( "The Docker daemon is not supported on this platform." )
2013-12-12 21:34:26 +00:00
)
2013-09-07 00:33:05 +00:00
2015-07-30 21:01:53 +00:00
// Daemon holds information about the Docker daemon.
2014-04-17 21:43:01 +00:00
type Daemon struct {
2015-11-18 22:20:54 +00:00
ID string
repository string
2016-01-15 23:55:46 +00:00
containers container . Store
2015-11-18 22:20:54 +00:00
execCommands * exec . Store
2017-01-26 00:54:18 +00:00
referenceStore refstore . Store
2015-11-14 00:59:01 +00:00
downloadManager * xfer . LayerDownloadManager
uploadManager * xfer . LayerUploadManager
2015-11-18 22:20:54 +00:00
distributionMetadataStore dmetadata . Store
trustKey libtrust . PrivateKey
idIndex * truncindex . TruncIndex
2017-01-23 11:23:07 +00:00
configStore * config . Config
2017-01-04 17:01:59 +00:00
statsCollector * stats . Collector
2015-12-18 18:36:17 +00:00
defaultLogConfig containertypes . LogConfig
2016-05-21 14:00:28 +00:00
RegistryService registry . Service
2015-11-18 22:20:54 +00:00
EventsService * events . Events
netController libnetwork . NetworkController
volumes * store . VolumeStore
2017-01-23 11:23:07 +00:00
discoveryWatcher discovery . Reloader
2015-11-18 22:20:54 +00:00
root string
2016-01-11 19:44:34 +00:00
seccompEnabled bool
2016-12-19 12:22:45 +00:00
apparmorEnabled bool
2015-11-18 22:20:54 +00:00
shutdown bool
2017-05-19 22:06:46 +00:00
idMappings * idtools . IDMappings
2015-11-18 22:20:54 +00:00
layerStore layer . Store
imageStore image . Store
2016-12-12 23:05:53 +00:00
PluginStore * plugin . Store // todo: remove
pluginManager * plugin . Manager
2015-09-04 00:51:04 +00:00
nameIndex * registrar . Registrar
linkIndex * linkIndex
2016-03-18 18:50:19 +00:00
containerd libcontainerd . Client
2016-06-02 18:10:55 +00:00
containerdRemote libcontainerd . Remote
2016-03-18 18:50:19 +00:00
defaultIsolation containertypes . Isolation // Default isolation mode on Windows
2016-06-14 02:52:49 +00:00
clusterProvider cluster . Provider
2016-10-18 04:36:52 +00:00
cluster Cluster
2017-04-14 01:56:50 +00:00
metricsPluginListener net . Listener
2016-09-02 13:20:54 +00:00
2017-01-04 17:01:59 +00:00
machineMemory uint64
2016-09-02 13:20:54 +00:00
seccompProfile [ ] byte
seccompProfilePath string
2017-04-12 20:59:59 +00:00
2017-04-12 21:04:49 +00:00
diskUsageRunning int32
pruneRunning int32
Don't create source directory while the daemon is being shutdown, fix #30348
If a container mount the socket the daemon is listening on into
container while the daemon is being shutdown, the socket will
not exist on the host, then daemon will assume it's a directory
and create it on the host, this will cause the daemon can't start
next time.
fix issue https://github.com/moby/moby/issues/30348
To reproduce this issue, you can add following code
```
--- a/daemon/oci_linux.go
+++ b/daemon/oci_linux.go
@@ -8,6 +8,7 @@ import (
"sort"
"strconv"
"strings"
+ "time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
@@ -666,7 +667,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
if err := daemon.setupIpcDirs(c); err != nil {
return nil, err
}
-
+ fmt.Printf("===please stop the daemon===\n")
+ time.Sleep(time.Second * 2)
ms, err := daemon.setupMounts(c)
if err != nil {
return nil, err
```
step1 run a container which has `--restart always` and `-v /var/run/docker.sock:/sock`
```
$ docker run -ti --restart always -v /var/run/docker.sock:/sock busybox
/ #
```
step2 exit the the container
```
/ # exit
```
and kill the daemon when you see
```
===please stop the daemon===
```
in the daemon log
The daemon can't restart again and fail with `can't create unix socket /var/run/docker.sock: is a directory`.
Signed-off-by: Lei Jitang <leijitang@huawei.com>
2017-05-22 07:44:01 +00:00
hosts map [ string ] bool // hosts stores the addresses the daemon is listening on
2017-06-08 10:55:20 +00:00
startupDone chan struct { }
Don't create source directory while the daemon is being shutdown, fix #30348
If a container mount the socket the daemon is listening on into
container while the daemon is being shutdown, the socket will
not exist on the host, then daemon will assume it's a directory
and create it on the host, this will cause the daemon can't start
next time.
fix issue https://github.com/moby/moby/issues/30348
To reproduce this issue, you can add following code
```
--- a/daemon/oci_linux.go
+++ b/daemon/oci_linux.go
@@ -8,6 +8,7 @@ import (
"sort"
"strconv"
"strings"
+ "time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
@@ -666,7 +667,8 @@ func (daemon *Daemon) createSpec(c *container.Container) (*libcontainerd.Spec, e
if err := daemon.setupIpcDirs(c); err != nil {
return nil, err
}
-
+ fmt.Printf("===please stop the daemon===\n")
+ time.Sleep(time.Second * 2)
ms, err := daemon.setupMounts(c)
if err != nil {
return nil, err
```
step1 run a container which has `--restart always` and `-v /var/run/docker.sock:/sock`
```
$ docker run -ti --restart always -v /var/run/docker.sock:/sock busybox
/ #
```
step2 exit the the container
```
/ # exit
```
and kill the daemon when you see
```
===please stop the daemon===
```
in the daemon log
The daemon can't restart again and fail with `can't create unix socket /var/run/docker.sock: is a directory`.
Signed-off-by: Lei Jitang <leijitang@huawei.com>
2017-05-22 07:44:01 +00:00
}
// StoreHosts stores the addresses the daemon is listening on
func ( daemon * Daemon ) StoreHosts ( hosts [ ] string ) {
if daemon . hosts == nil {
daemon . hosts = make ( map [ string ] bool )
}
for _ , h := range hosts {
daemon . hosts [ h ] = true
}
2013-03-21 07:25:00 +00:00
}
2016-10-06 14:09:54 +00:00
// HasExperimental returns whether the experimental features of the daemon are enabled or not
func ( daemon * Daemon ) HasExperimental ( ) bool {
if daemon . configStore != nil && daemon . configStore . Experimental {
return true
}
return false
}
2015-09-29 17:51:40 +00:00
func ( daemon * Daemon ) restore ( ) error {
2014-06-06 00:31:58 +00:00
var (
2015-12-16 20:32:16 +00:00
currentDriver = daemon . GraphDriverName ( )
2015-09-04 00:51:04 +00:00
containers = make ( map [ string ] * container . Container )
2014-06-06 00:31:58 +00:00
)
2014-05-30 18:03:56 +00:00
2016-09-28 06:41:19 +00:00
logrus . Info ( "Loading containers: start." )
2014-04-17 21:43:01 +00:00
dir , err := ioutil . ReadDir ( daemon . repository )
2013-01-19 00:13:39 +00:00
if err != nil {
return err
}
2013-10-24 23:49:28 +00:00
2013-12-18 18:43:42 +00:00
for _ , v := range dir {
2013-03-21 07:25:00 +00:00
id := v . Name ( )
2014-04-17 21:43:01 +00:00
container , err := daemon . load ( id )
2013-01-19 00:13:39 +00:00
if err != nil {
2015-03-26 22:22:04 +00:00
logrus . Errorf ( "Failed to load container %v: %v" , id , err )
2013-01-19 00:13:39 +00:00
continue
}
2013-11-15 06:52:08 +00:00
// Ignore the container if it does not support the current driver being used by the graph
2014-08-06 17:40:43 +00:00
if ( container . Driver == "" && currentDriver == "aufs" ) || container . Driver == currentDriver {
2016-01-27 01:20:30 +00:00
rwlayer , err := daemon . layerStore . GetRWLayer ( container . ID )
if err != nil {
logrus . Errorf ( "Failed to load container mount %v: %v" , id , err )
continue
}
container . RWLayer = rwlayer
2015-03-26 22:22:04 +00:00
logrus . Debugf ( "Loaded container %v" , container . ID )
2014-08-06 17:40:43 +00:00
2015-09-04 00:51:04 +00:00
containers [ container . ID ] = container
2013-11-15 06:52:08 +00:00
} else {
2015-03-26 22:22:04 +00:00
logrus . Debugf ( "Cannot load container %s because it was created with another graph driver." , container . ID )
2013-11-15 06:52:08 +00:00
}
2013-10-05 02:25:15 +00:00
}
2016-03-01 16:30:27 +00:00
removeContainers := make ( map [ string ] * container . Container )
2015-11-24 20:25:12 +00:00
restartContainers := make ( map [ * container . Container ] chan struct { } )
2016-06-14 16:13:53 +00:00
activeSandboxes := make ( map [ string ] interface { } )
2016-09-29 15:35:10 +00:00
for id , c := range containers {
2015-09-04 00:51:04 +00:00
if err := daemon . registerName ( c ) ; err != nil {
logrus . Errorf ( "Failed to register container %s: %s" , c . ID , err )
2016-09-29 15:35:10 +00:00
delete ( containers , id )
2015-09-04 00:51:04 +00:00
continue
2015-11-24 20:25:12 +00:00
}
2017-02-06 04:27:40 +00:00
daemon . Register ( c )
2016-05-07 16:20:24 +00:00
2016-09-06 13:49:10 +00:00
// verify that all volumes valid and have been migrated from the pre-1.7 layout
if err := daemon . verifyVolumesInfo ( c ) ; err != nil {
// don't skip the container due to error
logrus . Errorf ( "Failed to verify volumes for container '%s': %v" , c . ID , err )
}
2016-05-07 16:20:24 +00:00
// The LogConfig.Type is empty if the container was created before docker 1.12 with default log driver.
// We should rewrite it to use the daemon defaults.
// Fixes https://github.com/docker/docker/issues/22536
if c . HostConfig . LogConfig . Type == "" {
if err := daemon . mergeAndVerifyLogConfig ( & c . HostConfig . LogConfig ) ; err != nil {
logrus . Errorf ( "Failed to verify log config for container %s: %q" , c . ID , err )
continue
}
}
2016-03-18 18:50:19 +00:00
}
2016-11-30 18:59:54 +00:00
2016-03-18 18:50:19 +00:00
var wg sync . WaitGroup
var mapLock sync . Mutex
for _ , c := range containers {
wg . Add ( 1 )
go func ( c * container . Container ) {
defer wg . Done ( )
2017-04-25 17:05:21 +00:00
daemon . backportMountSpec ( c )
if err := c . ToDiskLocking ( ) ; err != nil {
logrus . WithError ( err ) . WithField ( "container" , c . ID ) . Error ( "error saving backported mountspec to disk" )
2016-08-04 19:34:52 +00:00
}
2017-04-25 17:05:21 +00:00
daemon . setStateCounter ( c )
2016-03-18 18:50:19 +00:00
if c . IsRunning ( ) || c . IsPaused ( ) {
2016-10-05 20:29:56 +00:00
c . RestartManager ( ) . Cancel ( ) // manually start containers because some need to wait for swarm networking
2016-10-17 21:39:52 +00:00
if err := daemon . containerd . Restore ( c . ID , c . InitializeStdio ) ; err != nil {
2016-07-11 15:55:39 +00:00
logrus . Errorf ( "Failed to restore %s with containerd: %s" , c . ID , err )
2016-03-18 18:50:19 +00:00
return
}
2016-12-29 01:08:03 +00:00
// we call Mount and then Unmount to get BaseFs of the container
if err := daemon . Mount ( c ) ; err != nil {
// The mount is unlikely to fail. However, in case mount fails
// the container should be allowed to restore here. Some functionalities
// (like docker exec -u user) might be missing but container is able to be
// stopped/restarted/removed.
// See #29365 for related information.
// The error is only logged here.
logrus . Warnf ( "Failed to mount container on getting BaseFs path %v: %v" , c . ID , err )
} else {
if err := daemon . Unmount ( c ) ; err != nil {
logrus . Warnf ( "Failed to umount container on getting BaseFs path %v: %v" , c . ID , err )
}
}
2016-10-05 20:29:56 +00:00
c . ResetRestartManager ( false )
2016-06-16 11:54:36 +00:00
if ! c . HostConfig . NetworkMode . IsContainer ( ) && c . IsRunning ( ) {
2016-06-14 16:13:53 +00:00
options , err := daemon . buildSandboxOptions ( c )
if err != nil {
logrus . Warnf ( "Failed build sandbox option to restore container %s: %v" , c . ID , err )
}
mapLock . Lock ( )
activeSandboxes [ c . NetworkSettings . SandboxID ] = options
mapLock . Unlock ( )
}
2016-03-18 18:50:19 +00:00
}
// fixme: only if not running
// get list of containers we need to restart
2016-03-01 16:30:27 +00:00
if ! c . IsRunning ( ) && ! c . IsPaused ( ) {
2016-09-09 16:55:57 +00:00
// Do not autostart containers which
// has endpoints in a swarm scope
// network yet since the cluster is
// not initialized yet. We will start
// it after the cluster is
// initialized.
if daemon . configStore . AutoRestart && c . ShouldRestart ( ) && ! c . NetworkSettings . HasSwarmEndpoint {
2016-03-01 16:30:27 +00:00
mapLock . Lock ( )
restartContainers [ c ] = make ( chan struct { } )
mapLock . Unlock ( )
} else if c . HostConfig != nil && c . HostConfig . AutoRemove {
2016-08-29 23:58:01 +00:00
mapLock . Lock ( )
2016-03-01 16:30:27 +00:00
removeContainers [ c . ID ] = c
2016-08-29 23:58:01 +00:00
mapLock . Unlock ( )
2016-03-01 16:30:27 +00:00
}
2016-03-18 18:50:19 +00:00
}
2015-09-04 00:51:04 +00:00
2016-04-29 18:38:13 +00:00
if c . RemovalInProgress {
// We probably crashed in the middle of a removal, reset
// the flag.
//
// We DO NOT remove the container here as we do not
// know if the user had requested for either the
// associated volumes, network links or both to also
// be removed. So we put the container in the "dead"
// state and leave further processing up to them.
logrus . Debugf ( "Resetting RemovalInProgress flag from %v" , c . ID )
c . ResetRemovalInProgress ( )
c . SetDead ( )
c . ToDisk ( )
}
2016-03-18 18:50:19 +00:00
} ( c )
2015-11-21 18:45:34 +00:00
}
2016-03-18 18:50:19 +00:00
wg . Wait ( )
2016-06-14 16:13:53 +00:00
daemon . netController , err = daemon . initNetworkController ( daemon . configStore , activeSandboxes )
if err != nil {
return fmt . Errorf ( "Error initializing network controller: %v" , err )
}
2015-11-21 18:45:34 +00:00
2015-09-04 00:51:04 +00:00
// Now that all the containers are registered, register the links
for _ , c := range containers {
if err := daemon . registerLinks ( c , c . HostConfig ) ; err != nil {
logrus . Errorf ( "failed to register link for container %s: %v" , c . ID , err )
2015-11-24 20:25:12 +00:00
}
}
2014-08-06 17:40:43 +00:00
2015-11-24 20:25:12 +00:00
group := sync . WaitGroup { }
for c , notifier := range restartContainers {
group . Add ( 1 )
2015-09-04 00:51:04 +00:00
go func ( c * container . Container , chNotify chan struct { } ) {
2015-11-24 20:25:12 +00:00
defer group . Done ( )
2015-09-04 00:51:04 +00:00
logrus . Debugf ( "Starting container %s" , c . ID )
2014-08-06 17:40:43 +00:00
2015-11-24 20:25:12 +00:00
// ignore errors here as this is a best effort to wait for children to be
// running before we try to start the container
2015-09-04 00:51:04 +00:00
children := daemon . children ( c )
2015-11-24 20:25:12 +00:00
timeout := time . After ( 5 * time . Second )
for _ , child := range children {
if notifier , exists := restartContainers [ child ] ; exists {
select {
case <- notifier :
case <- timeout :
}
2014-08-06 17:40:43 +00:00
}
}
2016-05-04 14:13:23 +00:00
// Make sure networks are available before starting
daemon . waitForNetworks ( c )
2016-09-19 16:01:16 +00:00
if err := daemon . containerStart ( c , "" , "" , true ) ; err != nil {
2015-09-04 00:51:04 +00:00
logrus . Errorf ( "Failed to start container %s: %s" , c . ID , err )
2015-11-24 20:25:12 +00:00
}
close ( chNotify )
} ( c , notifier )
2015-09-04 00:51:04 +00:00
2014-06-06 00:31:58 +00:00
}
2015-05-19 20:05:25 +00:00
group . Wait ( )
2014-06-06 00:31:58 +00:00
2016-03-01 16:30:27 +00:00
removeGroup := sync . WaitGroup { }
for id := range removeContainers {
removeGroup . Add ( 1 )
go func ( cid string ) {
if err := daemon . ContainerRm ( cid , & types . ContainerRmConfig { ForceRemove : true , RemoveVolume : true } ) ; err != nil {
logrus . Errorf ( "Failed to remove container %s: %s" , cid , err )
}
2016-06-09 15:32:20 +00:00
removeGroup . Done ( )
2016-03-01 16:30:27 +00:00
} ( id )
}
removeGroup . Wait ( )
2016-01-20 17:06:03 +00:00
// any containers that were started above would already have had this done,
// however we need to now prepare the mountpoints for the rest of the containers as well.
// This shouldn't cause any issue running on the containers that already had this run.
// This must be run after any containers with a restart policy so that containerized plugins
// can have a chance to be running before we try to initialize them.
for _ , c := range containers {
2016-01-27 07:43:40 +00:00
// if the container has restart policy, do not
// prepare the mountpoints since it has been done on restarting.
// This is to speed up the daemon start when a restart container
2016-12-19 12:33:36 +00:00
// has a volume and the volume driver is not available.
2016-01-27 07:43:40 +00:00
if _ , ok := restartContainers [ c ] ; ok {
continue
2016-03-01 16:30:27 +00:00
} else if _ , ok := removeContainers [ c . ID ] ; ok {
// container is automatically removed, skip it.
continue
2016-01-27 07:43:40 +00:00
}
2016-03-01 16:30:27 +00:00
2016-01-20 17:06:03 +00:00
group . Add ( 1 )
go func ( c * container . Container ) {
defer group . Done ( )
if err := daemon . prepareMountPoints ( c ) ; err != nil {
logrus . Error ( err )
}
} ( c )
}
group . Wait ( )
2016-09-28 06:41:19 +00:00
logrus . Info ( "Loading containers: done." )
2013-10-05 02:25:15 +00:00
2013-01-19 00:13:39 +00:00
return nil
}
2016-09-09 16:55:57 +00:00
// RestartSwarmContainers restarts any autostart container which has a
// swarm endpoint.
func ( daemon * Daemon ) RestartSwarmContainers ( ) {
group := sync . WaitGroup { }
for _ , c := range daemon . List ( ) {
if ! c . IsRunning ( ) && ! c . IsPaused ( ) {
// Autostart all the containers which has a
// swarm endpoint now that the cluster is
// initialized.
if daemon . configStore . AutoRestart && c . ShouldRestart ( ) && c . NetworkSettings . HasSwarmEndpoint {
group . Add ( 1 )
go func ( c * container . Container ) {
defer group . Done ( )
2016-09-19 16:01:16 +00:00
if err := daemon . containerStart ( c , "" , "" , true ) ; err != nil {
2016-09-09 16:55:57 +00:00
logrus . Error ( err )
}
} ( c )
}
}
}
group . Wait ( )
}
2016-05-04 14:13:23 +00:00
// waitForNetworks is used during daemon initialization when starting up containers
// It ensures that all of a container's networks are available before the daemon tries to start the container.
// In practice it just makes sure the discovery service is available for containers which use a network that require discovery.
func ( daemon * Daemon ) waitForNetworks ( c * container . Container ) {
if daemon . discoveryWatcher == nil {
return
}
// Make sure if the container has a network that requires discovery that the discovery service is available before starting
for netName := range c . NetworkSettings . Networks {
2016-07-03 12:47:39 +00:00
// If we get `ErrNoSuchNetwork` here, we can assume that it is due to discovery not being ready
2016-05-04 14:13:23 +00:00
// Most likely this is because the K/V store used for discovery is in a container and needs to be started
if _ , err := daemon . netController . NetworkByName ( netName ) ; err != nil {
if _ , ok := err . ( libnetwork . ErrNoSuchNetwork ) ; ! ok {
continue
}
// use a longish timeout here due to some slowdowns in libnetwork if the k/v store is on anything other than --net=host
// FIXME: why is this slow???
logrus . Debugf ( "Container %s waiting for network to be ready" , c . Name )
select {
case <- daemon . discoveryWatcher . ReadyCh ( ) :
case <- time . After ( 60 * time . Second ) :
}
return
}
}
}
2015-09-04 00:51:04 +00:00
func ( daemon * Daemon ) children ( c * container . Container ) map [ string ] * container . Container {
return daemon . linkIndex . children ( c )
2013-10-05 02:25:15 +00:00
}
2015-07-30 21:01:53 +00:00
// parents returns the names of the parent containers of the container
// with the given name.
2015-09-04 00:51:04 +00:00
func ( daemon * Daemon ) parents ( c * container . Container ) map [ string ] * container . Container {
return daemon . linkIndex . parents ( c )
2014-07-14 23:19:37 +00:00
}
2015-11-12 19:55:17 +00:00
func ( daemon * Daemon ) registerLink ( parent , child * container . Container , alias string ) error {
2015-09-04 00:51:04 +00:00
fullName := path . Join ( parent . Name , alias )
if err := daemon . nameIndex . Reserve ( fullName , child . ID ) ; err != nil {
2016-01-20 21:24:16 +00:00
if err == registrar . ErrNameReserved {
logrus . Warnf ( "error registering link for %s, to %s, as alias %s, ignoring: %v" , parent . ID , child . ID , alias , err )
return nil
}
2013-10-05 02:25:15 +00:00
return err
}
2015-09-04 00:51:04 +00:00
daemon . linkIndex . link ( parent , child , fullName )
2013-10-28 23:58:59 +00:00
return nil
2013-10-05 02:25:15 +00:00
}
2017-01-14 04:14:03 +00:00
// DaemonJoinsCluster informs the daemon has joined the cluster and provides
// the handler to query the cluster component
func ( daemon * Daemon ) DaemonJoinsCluster ( clusterProvider cluster . Provider ) {
daemon . setClusterProvider ( clusterProvider )
}
// DaemonLeavesCluster informs the daemon has left the cluster
func ( daemon * Daemon ) DaemonLeavesCluster ( ) {
// Daemon is in charge of removing the attachable networks with
// connected containers when the node leaves the swarm
daemon . clearAttachableNetworks ( )
2017-03-31 21:07:55 +00:00
// We no longer need the cluster provider, stop it now so that
// the network agent will stop listening to cluster events.
2017-01-14 04:14:03 +00:00
daemon . setClusterProvider ( nil )
2017-03-31 21:07:55 +00:00
// Wait for the networking cluster agent to stop
daemon . netController . AgentStopWait ( )
// Daemon is in charge of removing the ingress network when the
// node leaves the swarm. Wait for job to be done or timeout.
// This is called also on graceful daemon shutdown. We need to
// wait, because the ingress release has to happen before the
// network controller is stopped.
if done , err := daemon . ReleaseIngress ( ) ; err == nil {
select {
case <- done :
case <- time . After ( 5 * time . Second ) :
logrus . Warnf ( "timeout while waiting for ingress network removal" )
}
} else {
logrus . Warnf ( "failed to initiate ingress network removal: %v" , err )
}
2017-01-14 04:14:03 +00:00
}
// setClusterProvider sets a component for querying the current cluster state.
func ( daemon * Daemon ) setClusterProvider ( clusterProvider cluster . Provider ) {
2016-06-14 02:52:49 +00:00
daemon . clusterProvider = clusterProvider
daemon . netController . SetClusterProvider ( clusterProvider )
}
2016-06-14 16:13:53 +00:00
// IsSwarmCompatible verifies if the current daemon
// configuration is compatible with the swarm mode
func ( daemon * Daemon ) IsSwarmCompatible ( ) error {
if daemon . configStore == nil {
return nil
}
2017-01-23 11:23:07 +00:00
return daemon . configStore . IsSwarmCompatible ( )
2016-06-14 16:13:53 +00:00
}
2015-07-30 21:01:53 +00:00
// NewDaemon sets up everything for the daemon to be able to service
// requests from the webserver.
2017-03-17 21:57:23 +00:00
func NewDaemon ( config * config . Config , registryService registry . Service , containerdRemote libcontainerd . Remote , pluginStore * plugin . Store ) ( daemon * Daemon , err error ) {
2015-06-15 23:33:02 +00:00
setDefaultMtu ( config )
2016-06-02 00:29:06 +00:00
// Ensure that we have a correct root key limit for launching containers.
if err := ModifyRootKeyLimit ( ) ; err != nil {
2016-11-08 21:06:24 +00:00
logrus . Warnf ( "unable to modify root key limit, number of containers could be limited by this quota: %v" , err )
2016-06-02 00:29:06 +00:00
}
2016-01-23 02:15:09 +00:00
// Ensure we have compatible and valid configuration options
if err := verifyDaemonSettings ( config ) ; err != nil {
2015-05-15 23:34:26 +00:00
return nil , err
2014-09-17 03:00:15 +00:00
}
2015-05-15 23:34:26 +00:00
// Do we have a disabled network?
2015-06-30 17:34:15 +00:00
config . DisableBridge = isBridgeNetworkDisabled ( config )
2014-08-10 01:18:32 +00:00
2015-07-11 19:32:08 +00:00
// Verify the platform is supported as a daemon
2015-08-07 16:33:29 +00:00
if ! platformSupported {
2015-07-30 21:01:53 +00:00
return nil , errSystemNotSupported
2015-07-11 19:32:08 +00:00
}
// Validate platform-specific requirements
2015-05-15 23:34:26 +00:00
if err := checkSystem ( ) ; err != nil {
2014-09-16 17:42:59 +00:00
return nil , err
2014-07-30 06:51:43 +00:00
}
2017-05-19 22:06:46 +00:00
idMappings , err := setupRemappedRoot ( config )
2015-10-08 15:51:41 +00:00
if err != nil {
return nil , err
}
2017-05-31 21:56:23 +00:00
rootIDs := idMappings . RootPair ( )
2016-07-11 22:26:23 +00:00
if err := setupDaemonProcess ( config ) ; err != nil {
2014-05-10 01:05:54 +00:00
return nil , err
}
2015-06-23 12:53:18 +00:00
// set up the tmpDir to use a canonical path
2017-05-19 22:06:46 +00:00
tmp , err := prepareTempDir ( config . Root , rootIDs )
2015-06-23 12:53:18 +00:00
if err != nil {
return nil , fmt . Errorf ( "Unable to get the TempDir under %s: %s" , config . Root , err )
}
2017-06-01 00:11:42 +00:00
realTmp , err := getRealPath ( tmp )
2015-06-23 12:53:18 +00:00
if err != nil {
return nil , fmt . Errorf ( "Unable to get the full path to the TempDir (%s): %s" , tmp , err )
}
os . Setenv ( "TMPDIR" , realTmp )
2017-06-08 10:55:20 +00:00
d := & Daemon {
configStore : config ,
startupDone : make ( chan struct { } ) ,
}
2015-12-16 20:32:16 +00:00
// Ensure the daemon is properly shutdown if there is a failure during
// initialization
2015-04-27 21:11:29 +00:00
defer func ( ) {
if err != nil {
2015-09-29 17:51:40 +00:00
if err := d . Shutdown ( ) ; err != nil {
2015-04-27 21:11:29 +00:00
logrus . Error ( err )
}
2015-03-11 14:33:06 +00:00
}
2015-04-27 21:11:29 +00:00
} ( )
2013-11-07 20:34:01 +00:00
2017-04-04 14:23:14 +00:00
// set up SIGUSR1 handler on Unix-like systems, or a Win32 global event
// on Windows to dump Go routine stacks
stackDumpDir := config . Root
if execRoot := config . GetExecRoot ( ) ; execRoot != "" {
stackDumpDir = execRoot
}
d . setupDumpStackTrap ( stackDumpDir )
2016-09-02 13:20:54 +00:00
if err := d . setupSeccompProfile ( ) ; err != nil {
return nil , err
}
2016-03-18 18:50:19 +00:00
// Set the default isolation mode (only applicable on Windows)
if err := d . setDefaultIsolation ( ) ; err != nil {
return nil , fmt . Errorf ( "error setting default isolation mode: %v" , err )
}
2015-04-09 04:23:30 +00:00
logrus . Debugf ( "Using default logging driver %s" , config . LogConfig . Type )
2015-12-02 10:26:30 +00:00
if err := configureMaxThreads ( config ) ; err != nil {
logrus . Warnf ( "Failed to configure golang's threads limit: %v" , err )
}
2016-12-05 13:12:17 +00:00
if err := ensureDefaultAppArmorProfile ( ) ; err != nil {
logrus . Errorf ( err . Error ( ) )
}
2015-05-15 23:34:26 +00:00
daemonRepo := filepath . Join ( config . Root , "containers" )
2017-05-19 22:06:46 +00:00
if err := idtools . MkdirAllAndChown ( daemonRepo , 0700 , rootIDs ) ; err != nil && ! os . IsExist ( err ) {
2013-03-14 01:48:50 +00:00
return nil , err
}
2016-06-07 19:15:50 +00:00
if runtime . GOOS == "windows" {
2016-11-04 19:42:21 +00:00
if err := system . MkdirAll ( filepath . Join ( config . Root , "credentialspecs" ) , 0 ) ; err != nil && ! os . IsExist ( err ) {
2016-06-07 19:15:50 +00:00
return nil , err
}
}
2015-12-16 20:32:16 +00:00
driverName := os . Getenv ( "DOCKER_DRIVER" )
if driverName == "" {
driverName = config . GraphDriver
}
2016-09-08 00:01:10 +00:00
2016-11-18 21:54:11 +00:00
d . RegistryService = registryService
2017-03-17 21:57:23 +00:00
d . PluginStore = pluginStore
2016-11-14 18:53:53 +00:00
logger . RegisterPluginGetter ( d . PluginStore )
2017-03-17 21:57:23 +00:00
2017-04-14 01:56:50 +00:00
metricsSockPath , err := d . listenMetricsSock ( )
if err != nil {
return nil , err
}
registerMetricsPluginCallback ( d . PluginStore , metricsSockPath )
2016-11-18 21:54:11 +00:00
// Plugin system initialization should happen before restore. Do not change order.
2016-12-12 23:05:53 +00:00
d . pluginManager , err = plugin . NewManager ( plugin . ManagerConfig {
Root : filepath . Join ( config . Root , "plugins" ) ,
2017-02-02 19:22:12 +00:00
ExecRoot : getPluginExecRoot ( config . Root ) ,
2016-12-12 23:05:53 +00:00
Store : d . PluginStore ,
Executor : containerdRemote ,
RegistryService : registryService ,
LiveRestoreEnabled : config . LiveRestoreEnabled ,
LogPluginEvent : d . LogPluginEvent , // todo: make private
2017-03-17 21:57:23 +00:00
AuthzMiddleware : config . AuthzMiddleware ,
2016-12-12 23:05:53 +00:00
} )
if err != nil {
return nil , errors . Wrap ( err , "couldn't create plugin manager" )
2016-11-18 21:54:11 +00:00
}
2016-09-08 00:01:10 +00:00
2015-12-16 20:32:16 +00:00
d . layerStore , err = layer . NewStoreFromOptions ( layer . StoreOptions {
StorePath : config . Root ,
2015-12-30 06:18:12 +00:00
MetadataStorePathTemplate : filepath . Join ( config . Root , "image" , "%s" , "layerdb" ) ,
2015-12-16 20:32:16 +00:00
GraphDriver : driverName ,
GraphDriverOptions : config . GraphOptions ,
2017-05-19 22:06:46 +00:00
IDMappings : idMappings ,
2016-10-07 21:53:17 +00:00
PluginGetter : d . PluginStore ,
2016-11-19 16:41:07 +00:00
ExperimentalEnabled : config . Experimental ,
2015-12-16 20:32:16 +00:00
} )
2015-11-18 22:20:54 +00:00
if err != nil {
return nil , err
}
2015-12-16 20:32:16 +00:00
graphDriver := d . layerStore . DriverName ( )
imageRoot := filepath . Join ( config . Root , "image" , graphDriver )
// Configure and validate the kernels security support
if err := configureKernelSecuritySupport ( config , graphDriver ) ; err != nil {
2015-11-18 22:20:54 +00:00
return nil , err
}
2016-05-06 04:45:55 +00:00
logrus . Debugf ( "Max Concurrent Downloads: %d" , * config . MaxConcurrentDownloads )
d . downloadManager = xfer . NewLayerDownloadManager ( d . layerStore , * config . MaxConcurrentDownloads )
logrus . Debugf ( "Max Concurrent Uploads: %d" , * config . MaxConcurrentUploads )
d . uploadManager = xfer . NewLayerUploadManager ( * config . MaxConcurrentUploads )
2015-11-18 22:20:54 +00:00
ifs , err := image . NewFSStoreBackend ( filepath . Join ( imageRoot , "imagedb" ) )
if err != nil {
return nil , err
}
2017-05-16 21:35:28 +00:00
// TODO LCOW @jhowardmsft. For now assume it's the runtime OS. This will be modified
// as the stores are split in a follow-up commit.
d . imageStore , err = image . NewImageStore ( ifs , runtime . GOOS , d . layerStore )
2013-02-27 01:45:46 +00:00
if err != nil {
return nil , err
}
2013-11-15 10:30:28 +00:00
2015-05-15 23:34:26 +00:00
// Configure the volumes driver
2017-05-19 22:06:46 +00:00
volStore , err := d . configureVolumes ( rootIDs )
2015-06-12 13:25:32 +00:00
if err != nil {
2013-04-06 01:00:10 +00:00
return nil , err
}
2014-08-28 14:18:08 +00:00
2015-01-07 22:59:12 +00:00
trustKey , err := api . LoadOrCreateTrustKey ( config . TrustKeyPath )
if err != nil {
return nil , err
}
2015-05-15 23:34:26 +00:00
trustDir := filepath . Join ( config . Root , "trust" )
Simplify and fix os.MkdirAll() usage
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.
[v2: a separate aufs commit is merged into this one]
[1] https://github.com/golang/go/blob/f9ed2f75/src/os/path.go
Signed-off-by: Kir Kolyshkin <kir@openvz.org>
2015-07-29 23:49:05 +00:00
if err := system . MkdirAll ( trustDir , 0700 ) ; err != nil {
2014-10-02 01:26:06 +00:00
return nil , err
}
2015-11-18 22:20:54 +00:00
distributionMetadataStore , err := dmetadata . NewFSMetadataStore ( filepath . Join ( imageRoot , "distribution" ) )
if err != nil {
return nil , err
}
2015-04-20 19:48:33 +00:00
eventsService := events . New ( )
2015-11-18 22:20:54 +00:00
2017-01-26 00:54:18 +00:00
referenceStore , err := refstore . NewReferenceStore ( filepath . Join ( imageRoot , "repositories.json" ) )
2015-04-20 19:48:33 +00:00
if err != nil {
2015-11-18 22:20:54 +00:00
return nil , fmt . Errorf ( "Couldn't create Tag store repositories: %s" , err )
2015-04-20 19:48:33 +00:00
}
2015-11-30 03:55:22 +00:00
migrationStart := time . Now ( )
2015-12-16 20:32:16 +00:00
if err := v1 . Migrate ( config . Root , graphDriver , d . layerStore , d . imageStore , referenceStore , distributionMetadataStore ) ; err != nil {
2016-02-09 17:44:33 +00:00
logrus . Errorf ( "Graph migration failed: %q. Your old graph data was found to be too inconsistent for upgrading to content-addressable storage. Some of the old data was probably not upgraded. We recommend starting over with a clean storage directory if possible." , err )
2015-07-25 00:49:43 +00:00
}
2015-11-30 03:55:22 +00:00
logrus . Infof ( "Graph migration to content-addressability took %.2f seconds" , time . Since ( migrationStart ) . Seconds ( ) )
2015-07-25 00:49:43 +00:00
2015-09-21 12:04:36 +00:00
// Discovery is only enabled when the daemon is launched with an address to advertise. When
2016-12-23 12:48:25 +00:00
// initialized, the daemon is registered and we can store the discovery backend as it's read-only
2015-12-10 23:35:10 +00:00
if err := d . initDiscovery ( config ) ; err != nil {
return nil , err
2015-09-21 12:04:36 +00:00
}
2014-03-05 09:40:55 +00:00
sysInfo := sysinfo . New ( false )
2015-06-19 22:29:47 +00:00
// Check if Devices cgroup is mounted, it is hard requirement for container security,
2016-05-26 11:08:53 +00:00
// on Linux.
if runtime . GOOS == "linux" && ! sysInfo . CgroupDevicesEnabled {
2016-12-25 06:37:31 +00:00
return nil , errors . New ( "Devices cgroup isn't mounted" )
2015-06-17 02:36:20 +00:00
}
2015-04-27 21:11:29 +00:00
d . ID = trustKey . PublicKey ( ) . KeyID ( )
d . repository = daemonRepo
2016-01-15 23:55:46 +00:00
d . containers = container . NewMemoryStore ( )
2015-11-20 22:35:16 +00:00
d . execCommands = exec . NewStore ( )
2015-12-04 21:55:15 +00:00
d . referenceStore = referenceStore
2015-11-18 22:20:54 +00:00
d . distributionMetadataStore = distributionMetadataStore
d . trustKey = trustKey
2015-04-27 21:11:29 +00:00
d . idIndex = truncindex . NewTruncIndex ( [ ] string { } )
2015-11-03 19:06:16 +00:00
d . statsCollector = d . newStatsCollector ( 1 * time . Second )
2015-12-10 23:35:10 +00:00
d . defaultLogConfig = containertypes . LogConfig {
Type : config . LogConfig . Type ,
Config : config . LogConfig . Config ,
}
2015-04-27 21:11:29 +00:00
d . EventsService = eventsService
2015-06-12 13:25:32 +00:00
d . volumes = volStore
2015-05-19 20:05:25 +00:00
d . root = config . Root
2017-05-19 22:06:46 +00:00
d . idMappings = idMappings
2016-01-11 19:44:34 +00:00
d . seccompEnabled = sysInfo . Seccomp
2016-12-19 12:22:45 +00:00
d . apparmorEnabled = sysInfo . AppArmor
2015-04-27 21:11:29 +00:00
2015-09-04 00:51:04 +00:00
d . nameIndex = registrar . NewRegistrar ( )
d . linkIndex = newLinkIndex ( )
2016-06-02 18:10:55 +00:00
d . containerdRemote = containerdRemote
2015-09-04 00:51:04 +00:00
2016-03-18 18:50:19 +00:00
go d . execCommandGC ( )
d . containerd , err = containerdRemote . Client ( d )
if err != nil {
2015-03-06 20:44:31 +00:00
return nil , err
}
2015-04-27 21:11:29 +00:00
2016-09-06 21:30:55 +00:00
if err := d . restore ( ) ; err != nil {
2016-07-18 15:02:12 +00:00
return nil , err
}
2017-06-08 10:55:20 +00:00
close ( d . startupDone )
2016-07-18 15:02:12 +00:00
2016-07-20 23:11:28 +00:00
// FIXME: this method never returns an error
info , _ := d . SystemInfo ( )
2017-04-24 11:32:01 +00:00
engineInfo . WithValues (
2016-07-20 23:11:28 +00:00
dockerversion . Version ,
dockerversion . GitCommit ,
info . Architecture ,
info . Driver ,
info . KernelVersion ,
info . OperatingSystem ,
2017-04-24 11:32:01 +00:00
info . OSType ,
info . ID ,
2016-07-20 23:11:28 +00:00
) . Set ( 1 )
engineCpus . Set ( float64 ( info . NCPU ) )
engineMemory . Set ( float64 ( info . MemTotal ) )
2015-05-06 22:39:29 +00:00
return d , nil
}
2017-06-08 10:55:20 +00:00
func ( daemon * Daemon ) waitForStartupDone ( ) {
<- daemon . startupDone
}
2015-11-12 19:55:17 +00:00
func ( daemon * Daemon ) shutdownContainer ( c * container . Container ) error {
2016-06-07 03:29:05 +00:00
stopTimeout := c . StopTimeout ( )
2015-10-29 22:11:35 +00:00
// TODO(windows): Handle docker restart with paused containers
2015-11-12 19:55:17 +00:00
if c . IsPaused ( ) {
2015-10-29 22:11:35 +00:00
// To terminate a process in freezer cgroup, we should send
// SIGTERM to this process then unfreeze it, and the process will
// force to terminate immediately.
2016-07-03 12:47:39 +00:00
logrus . Debugf ( "Found container %s is paused, sending SIGTERM before unpausing it" , c . ID )
2015-10-29 22:11:35 +00:00
sig , ok := signal . SignalMap [ "TERM" ]
if ! ok {
2016-12-25 06:37:31 +00:00
return errors . New ( "System does not support SIGTERM" )
2015-10-29 22:11:35 +00:00
}
2015-11-02 23:39:39 +00:00
if err := daemon . kill ( c , int ( sig ) ) ; err != nil {
2015-10-29 22:11:35 +00:00
return fmt . Errorf ( "sending SIGTERM to container %s with error: %v" , c . ID , err )
}
2015-11-02 23:39:39 +00:00
if err := daemon . containerUnpause ( c ) ; err != nil {
2015-10-29 22:11:35 +00:00
return fmt . Errorf ( "Failed to unpause container %s with error: %v" , c . ID , err )
}
2017-03-30 20:52:40 +00:00
ctx , cancel := context . WithTimeout ( context . Background ( ) , time . Duration ( stopTimeout ) * time . Second )
defer cancel ( )
// Wait with timeout for container to exit.
2017-03-31 03:01:41 +00:00
if status := <- c . Wait ( ctx , container . WaitConditionNotRunning ) ; status . Err ( ) != nil {
2016-06-07 03:29:05 +00:00
logrus . Debugf ( "container %s failed to exit in %d second of SIGTERM, sending SIGKILL to force" , c . ID , stopTimeout )
2015-10-29 22:11:35 +00:00
sig , ok := signal . SignalMap [ "KILL" ]
if ! ok {
2016-12-25 06:37:31 +00:00
return errors . New ( "System does not support SIGKILL" )
2015-10-29 22:11:35 +00:00
}
2015-11-02 23:39:39 +00:00
if err := daemon . kill ( c , int ( sig ) ) ; err != nil {
2015-10-29 22:11:35 +00:00
logrus . Errorf ( "Failed to SIGKILL container %s" , c . ID )
}
2017-03-30 20:52:40 +00:00
// Wait for exit again without a timeout.
// Explicitly ignore the result.
2017-03-31 03:01:41 +00:00
_ = <- c . Wait ( context . Background ( ) , container . WaitConditionNotRunning )
2017-03-30 20:52:40 +00:00
return status . Err ( )
2015-10-29 22:11:35 +00:00
}
}
2016-06-07 03:29:05 +00:00
// If container failed to exit in stopTimeout seconds of SIGTERM, then using the force
if err := daemon . containerStop ( c , stopTimeout ) ; err != nil {
2016-07-03 12:47:39 +00:00
return fmt . Errorf ( "Failed to stop container %s with error: %v" , c . ID , err )
2015-10-29 22:11:35 +00:00
}
2017-03-30 20:52:40 +00:00
// Wait without timeout for the container to exit.
// Ignore the result.
2017-03-31 03:01:41 +00:00
_ = <- c . Wait ( context . Background ( ) , container . WaitConditionNotRunning )
2015-10-29 22:11:35 +00:00
return nil
}
2016-05-26 21:07:30 +00:00
// ShutdownTimeout returns the shutdown timeout based on the max stopTimeout of the containers,
// and is limited by daemon's ShutdownTimeout.
2016-06-07 03:29:05 +00:00
func ( daemon * Daemon ) ShutdownTimeout ( ) int {
2016-05-26 21:07:30 +00:00
// By default we use daemon's ShutdownTimeout.
shutdownTimeout := daemon . configStore . ShutdownTimeout
2016-06-07 03:29:05 +00:00
graceTimeout := 5
if daemon . containers != nil {
for _ , c := range daemon . containers . List ( ) {
if shutdownTimeout >= 0 {
stopTimeout := c . StopTimeout ( )
if stopTimeout < 0 {
shutdownTimeout = - 1
} else {
if stopTimeout + graceTimeout > shutdownTimeout {
shutdownTimeout = stopTimeout + graceTimeout
}
}
}
}
}
return shutdownTimeout
}
2015-07-30 21:01:53 +00:00
// Shutdown stops the daemon.
2015-09-29 17:51:40 +00:00
func ( daemon * Daemon ) Shutdown ( ) error {
2015-08-05 21:09:08 +00:00
daemon . shutdown = true
2016-06-02 18:10:55 +00:00
// Keep mounts and networking running on daemon shutdown if
// we are to keep containers running and restore them.
2016-07-22 15:53:26 +00:00
2016-07-27 15:30:15 +00:00
if daemon . configStore . LiveRestoreEnabled && daemon . containers != nil {
2016-07-08 02:19:48 +00:00
// check if there are any running containers, if none we should do some cleanup
if ls , err := daemon . Containers ( & types . ContainerListOptions { } ) ; len ( ls ) != 0 || err != nil {
2017-04-14 01:56:50 +00:00
// metrics plugins still need some cleanup
daemon . cleanupMetricsPlugins ( )
2016-07-08 02:19:48 +00:00
return nil
}
2016-06-02 18:10:55 +00:00
}
2016-07-08 02:19:48 +00:00
2015-04-27 21:11:29 +00:00
if daemon . containers != nil {
2016-05-26 21:07:30 +00:00
logrus . Debugf ( "start clean shutdown of all containers with a %d seconds timeout..." , daemon . configStore . ShutdownTimeout )
2016-01-15 23:55:46 +00:00
daemon . containers . ApplyAll ( func ( c * container . Container ) {
if ! c . IsRunning ( ) {
return
2015-04-27 21:11:29 +00:00
}
2016-01-15 23:55:46 +00:00
logrus . Debugf ( "stopping %s" , c . ID )
if err := daemon . shutdownContainer ( c ) ; err != nil {
logrus . Errorf ( "Stop container error: %v" , err )
return
}
2016-03-18 18:50:19 +00:00
if mountid , err := daemon . layerStore . GetMountID ( c . ID ) ; err == nil {
daemon . cleanupMountsByID ( mountid )
}
2016-01-15 23:55:46 +00:00
logrus . Debugf ( "container stopped %s" , c . ID )
} )
2015-10-29 22:11:35 +00:00
}
2015-06-05 22:02:56 +00:00
2016-12-01 22:17:07 +00:00
if daemon . volumes != nil {
if err := daemon . volumes . Shutdown ( ) ; err != nil {
logrus . Errorf ( "Error shutting down volume store: %v" , err )
}
}
2016-11-30 01:00:02 +00:00
if daemon . layerStore != nil {
if err := daemon . layerStore . Cleanup ( ) ; err != nil {
logrus . Errorf ( "Error during layer Store.Cleanup(): %v" , err )
}
}
2017-03-31 21:07:55 +00:00
// If we are part of a cluster, clean up cluster's stuff
if daemon . clusterProvider != nil {
logrus . Debugf ( "start clean shutdown of cluster resources..." )
daemon . DaemonLeavesCluster ( )
}
2017-04-14 01:56:50 +00:00
daemon . cleanupMetricsPlugins ( )
2016-11-30 01:00:02 +00:00
// Shutdown plugins after containers and layerstore. Don't change the order.
2016-10-06 14:09:54 +00:00
daemon . pluginShutdown ( )
2016-10-03 22:42:46 +00:00
2015-10-29 22:11:35 +00:00
// trigger libnetwork Stop only if it's initialized
if daemon . netController != nil {
daemon . netController . Stop ( )
2015-04-27 21:11:29 +00:00
}
2014-03-25 23:21:07 +00:00
2015-08-03 22:05:34 +00:00
if err := daemon . cleanupMounts ( ) ; err != nil {
return err
}
2014-03-25 23:21:07 +00:00
return nil
}
2015-11-12 19:55:17 +00:00
// Mount sets container.BaseFS
2015-07-30 21:01:53 +00:00
// (is it not set coming in? why is it unset?)
2015-11-12 19:55:17 +00:00
func ( daemon * Daemon ) Mount ( container * container . Container ) error {
2015-12-16 22:13:50 +00:00
dir , err := container . RWLayer . Mount ( container . GetMountLabel ( ) )
2015-11-18 22:20:54 +00:00
if err != nil {
return err
}
logrus . Debugf ( "container mounted via layerStore: %v" , dir )
2015-05-15 23:34:26 +00:00
2015-11-12 19:55:17 +00:00
if container . BaseFS != dir {
2015-05-15 23:34:26 +00:00
// The mount path reported by the graph driver should always be trusted on Windows, since the
// volume path for a given mounted layer may change over time. This should only be an error
// on non-Windows operating systems.
2015-11-12 19:55:17 +00:00
if container . BaseFS != "" && runtime . GOOS != "windows" {
2015-11-18 22:20:54 +00:00
daemon . Unmount ( container )
2015-05-15 23:34:26 +00:00
return fmt . Errorf ( "Error: driver %s is returning inconsistent paths for container %s ('%s' then '%s')" ,
2015-12-16 20:32:16 +00:00
daemon . GraphDriverName ( ) , container . ID , container . BaseFS , dir )
2015-05-15 23:34:26 +00:00
}
2013-11-01 01:07:54 +00:00
}
2015-11-12 19:55:17 +00:00
container . BaseFS = dir // TODO: combine these fields
2013-11-07 20:34:01 +00:00
return nil
2013-11-01 01:07:54 +00:00
}
2015-11-03 01:06:09 +00:00
// Unmount unsets the container base filesystem
2016-03-18 18:50:19 +00:00
func ( daemon * Daemon ) Unmount ( container * container . Container ) error {
2015-12-16 22:13:50 +00:00
if err := container . RWLayer . Unmount ( ) ; err != nil {
2015-11-18 22:20:54 +00:00
logrus . Errorf ( "Error unmounting container %s: %s" , container . ID , err )
2016-03-18 18:50:19 +00:00
return err
2015-11-18 22:20:54 +00:00
}
2016-10-19 16:22:02 +00:00
2016-03-18 18:50:19 +00:00
return nil
2014-01-10 22:26:29 +00:00
}
2017-02-28 09:51:40 +00:00
// Subnets return the IPv4 and IPv6 subnets of networks that are manager by Docker.
func ( daemon * Daemon ) Subnets ( ) ( [ ] net . IPNet , [ ] net . IPNet ) {
var v4Subnets [ ] net . IPNet
var v6Subnets [ ] net . IPNet
2016-07-01 01:07:35 +00:00
managedNetworks := daemon . netController . Networks ( )
for _ , managedNetwork := range managedNetworks {
2017-02-28 09:51:40 +00:00
v4infos , v6infos := managedNetwork . Info ( ) . IpamInfo ( )
for _ , info := range v4infos {
if info . IPAMData . Pool != nil {
v4Subnets = append ( v4Subnets , * info . IPAMData . Pool )
2016-07-01 01:07:35 +00:00
}
}
2017-02-28 09:51:40 +00:00
for _ , info := range v6infos {
if info . IPAMData . Pool != nil {
v6Subnets = append ( v6Subnets , * info . IPAMData . Pool )
2016-07-01 01:07:35 +00:00
}
}
}
2017-02-28 09:51:40 +00:00
return v4Subnets , v6Subnets
2016-07-01 01:07:35 +00:00
}
2015-12-16 20:32:16 +00:00
// GraphDriverName returns the name of the graph driver used by the layer.Store
func ( daemon * Daemon ) GraphDriverName ( ) string {
return daemon . layerStore . DriverName ( )
2014-03-08 02:42:29 +00:00
}
2017-03-10 17:47:25 +00:00
// prepareTempDir prepares and returns the default directory to use
// for temporary files.
// If it doesn't exist, it is created. If it exists, its content is removed.
2017-05-19 22:06:46 +00:00
func prepareTempDir ( rootDir string , rootIDs idtools . IDPair ) ( string , error ) {
2015-03-29 18:51:17 +00:00
var tmpDir string
if tmpDir = os . Getenv ( "DOCKER_TMPDIR" ) ; tmpDir == "" {
tmpDir = filepath . Join ( rootDir , "tmp" )
2017-03-10 17:47:25 +00:00
newName := tmpDir + "-old"
2017-04-17 18:59:23 +00:00
if err := os . Rename ( tmpDir , newName ) ; err == nil {
2017-03-10 17:47:25 +00:00
go func ( ) {
if err := os . RemoveAll ( newName ) ; err != nil {
logrus . Warnf ( "failed to delete old tmp directory: %s" , newName )
}
} ( )
} else {
logrus . Warnf ( "failed to rename %s for background deletion: %s. Deleting synchronously" , tmpDir , err )
if err := os . RemoveAll ( tmpDir ) ; err != nil {
logrus . Warnf ( "failed to delete old tmp directory: %s" , tmpDir )
}
}
2015-03-29 18:51:17 +00:00
}
2017-03-10 17:47:25 +00:00
// We don't remove the content of tmpdir if it's not the default,
// it may hold things that do not belong to us.
2017-05-19 22:06:46 +00:00
return tmpDir , idtools . MkdirAllAndChown ( tmpDir , 0700 , rootIDs )
2015-04-16 06:31:52 +00:00
}
2015-04-23 02:23:02 +00:00
2015-11-18 22:20:54 +00:00
func ( daemon * Daemon ) setupInitLayer ( initPath string ) error {
2017-05-31 21:56:23 +00:00
rootIDs := daemon . idMappings . RootPair ( )
2017-05-19 22:06:46 +00:00
return initlayer . Setup ( initPath , rootIDs )
2015-11-18 22:20:54 +00:00
}
2017-01-23 11:23:07 +00:00
func setDefaultMtu ( conf * config . Config ) {
2015-06-15 23:33:02 +00:00
// do nothing if the config does not have the default 0 value.
2017-01-23 11:23:07 +00:00
if conf . Mtu != 0 {
2015-06-15 23:33:02 +00:00
return
}
2017-01-23 11:23:07 +00:00
conf . Mtu = config . DefaultNetworkMtu
2015-06-15 23:33:02 +00:00
}
2017-05-19 22:06:46 +00:00
func ( daemon * Daemon ) configureVolumes ( rootIDs idtools . IDPair ) ( * store . VolumeStore , error ) {
volumesDriver , err := local . New ( daemon . configStore . Root , rootIDs )
2015-09-16 21:18:24 +00:00
if err != nil {
return nil , err
}
2015-09-18 23:58:05 +00:00
2016-10-07 21:53:17 +00:00
volumedrivers . RegisterPluginGetter ( daemon . PluginStore )
2016-09-08 00:01:10 +00:00
2016-04-11 15:17:52 +00:00
if ! volumedrivers . Register ( volumesDriver , volumesDriver . Name ( ) ) {
2016-12-25 06:37:31 +00:00
return nil , errors . New ( "local volume driver could not be registered" )
2016-04-11 15:17:52 +00:00
}
2016-05-16 15:50:55 +00:00
return store . New ( daemon . configStore . Root )
2015-09-16 21:18:24 +00:00
}
2015-10-08 23:16:36 +00:00
2015-11-03 19:25:22 +00:00
// IsShuttingDown tells whether the daemon is shutting down or not
func ( daemon * Daemon ) IsShuttingDown ( ) bool {
return daemon . shutdown
}
2015-12-10 23:35:10 +00:00
// initDiscovery initializes the discovery watcher for this daemon.
2017-01-23 11:23:07 +00:00
func ( daemon * Daemon ) initDiscovery ( conf * config . Config ) error {
advertise , err := config . ParseClusterAdvertiseSettings ( conf . ClusterStore , conf . ClusterAdvertise )
2015-12-10 23:35:10 +00:00
if err != nil {
2017-01-23 11:23:07 +00:00
if err == discovery . ErrDiscoveryDisabled {
2015-12-10 23:35:10 +00:00
return nil
}
return err
}
2017-01-23 11:23:07 +00:00
conf . ClusterAdvertise = advertise
discoveryWatcher , err := discovery . Init ( conf . ClusterStore , conf . ClusterAdvertise , conf . ClusterOpts )
2015-12-10 23:35:10 +00:00
if err != nil {
return fmt . Errorf ( "discovery initialization failed (%v)" , err )
}
daemon . discoveryWatcher = discoveryWatcher
return nil
}
2017-01-23 11:23:07 +00:00
func isBridgeNetworkDisabled ( conf * config . Config ) bool {
return conf . BridgeConfig . Iface == config . DisableNetworkBridge
2016-03-10 04:33:21 +00:00
}
2017-01-23 11:23:07 +00:00
func ( daemon * Daemon ) networkOptions ( dconfig * config . Config , pg plugingetter . PluginGetter , activeSandboxes map [ string ] interface { } ) ( [ ] nwconfig . Option , error ) {
2016-03-10 04:33:21 +00:00
options := [ ] nwconfig . Option { }
if dconfig == nil {
return options , nil
}
2016-12-13 22:07:57 +00:00
options = append ( options , nwconfig . OptionExperimental ( dconfig . Experimental ) )
2016-03-10 04:33:21 +00:00
options = append ( options , nwconfig . OptionDataDir ( dconfig . Root ) )
2016-07-21 23:13:10 +00:00
options = append ( options , nwconfig . OptionExecRoot ( dconfig . GetExecRoot ( ) ) )
2016-03-10 04:33:21 +00:00
dd := runconfig . DefaultDaemonNetworkMode ( )
dn := runconfig . DefaultDaemonNetworkMode ( ) . NetworkName ( )
options = append ( options , nwconfig . OptionDefaultDriver ( string ( dd ) ) )
options = append ( options , nwconfig . OptionDefaultNetwork ( dn ) )
if strings . TrimSpace ( dconfig . ClusterStore ) != "" {
kv := strings . Split ( dconfig . ClusterStore , "://" )
if len ( kv ) != 2 {
2016-12-25 06:37:31 +00:00
return nil , errors . New ( "kv store daemon config must be of the form KV-PROVIDER://KV-URL" )
2016-03-10 04:33:21 +00:00
}
options = append ( options , nwconfig . OptionKVProvider ( kv [ 0 ] ) )
options = append ( options , nwconfig . OptionKVProviderURL ( kv [ 1 ] ) )
}
if len ( dconfig . ClusterOpts ) > 0 {
options = append ( options , nwconfig . OptionKVOpts ( dconfig . ClusterOpts ) )
}
if daemon . discoveryWatcher != nil {
options = append ( options , nwconfig . OptionDiscoveryWatcher ( daemon . discoveryWatcher ) )
}
if dconfig . ClusterAdvertise != "" {
options = append ( options , nwconfig . OptionDiscoveryAddress ( dconfig . ClusterAdvertise ) )
}
options = append ( options , nwconfig . OptionLabels ( dconfig . Labels ) )
options = append ( options , driverOptions ( dconfig ) ... )
2016-06-14 16:13:53 +00:00
2016-07-27 15:30:15 +00:00
if daemon . configStore != nil && daemon . configStore . LiveRestoreEnabled && len ( activeSandboxes ) != 0 {
2016-06-14 16:13:53 +00:00
options = append ( options , nwconfig . OptionActiveSandboxes ( activeSandboxes ) )
}
2016-09-26 17:08:52 +00:00
if pg != nil {
options = append ( options , nwconfig . OptionPluginGetter ( pg ) )
}
2016-03-10 04:33:21 +00:00
return options , nil
}
2016-03-18 18:50:19 +00:00
func copyBlkioEntry ( entries [ ] * containerd . BlkioStatsEntry ) [ ] types . BlkioStatEntry {
out := make ( [ ] types . BlkioStatEntry , len ( entries ) )
for i , re := range entries {
out [ i ] = types . BlkioStatEntry {
Major : re . Major ,
Minor : re . Minor ,
Op : re . Op ,
Value : re . Value ,
}
}
return out
}
2016-10-18 04:36:52 +00:00
// GetCluster returns the cluster
func ( daemon * Daemon ) GetCluster ( ) Cluster {
return daemon . cluster
}
// SetCluster sets the cluster
func ( daemon * Daemon ) SetCluster ( cluster Cluster ) {
daemon . cluster = cluster
}
2016-11-10 01:49:09 +00:00
func ( daemon * Daemon ) pluginShutdown ( ) {
2016-12-12 23:05:53 +00:00
manager := daemon . pluginManager
2016-11-10 01:49:09 +00:00
// Check for a valid manager object. In error conditions, daemon init can fail
// and shutdown called, before plugin manager is initialized.
if manager != nil {
manager . Shutdown ( )
}
}
2016-11-04 19:42:21 +00:00
2016-12-12 23:05:53 +00:00
// PluginManager returns current pluginManager associated with the daemon
func ( daemon * Daemon ) PluginManager ( ) * plugin . Manager { // set up before daemon to avoid this method
return daemon . pluginManager
}
2017-01-20 01:09:37 +00:00
// PluginGetter returns current pluginStore associated with the daemon
func ( daemon * Daemon ) PluginGetter ( ) * plugin . Store {
return daemon . PluginStore
}
2016-11-04 19:42:21 +00:00
// CreateDaemonRoot creates the root for the daemon
2017-01-23 11:23:07 +00:00
func CreateDaemonRoot ( config * config . Config ) error {
2016-11-04 19:42:21 +00:00
// get the canonical path to the Docker root directory
var realRoot string
if _ , err := os . Stat ( config . Root ) ; err != nil && os . IsNotExist ( err ) {
realRoot = config . Root
} else {
2017-06-01 00:11:42 +00:00
realRoot , err = getRealPath ( config . Root )
2016-11-04 19:42:21 +00:00
if err != nil {
return fmt . Errorf ( "Unable to get the full path to root (%s): %s" , config . Root , err )
}
}
2017-05-19 22:06:46 +00:00
idMappings , err := setupRemappedRoot ( config )
2016-11-04 19:42:21 +00:00
if err != nil {
return err
}
2017-05-31 21:56:23 +00:00
return setupDaemonRoot ( config , realRoot , idMappings . RootPair ( ) )
2016-11-04 19:42:21 +00:00
}