From ae6533484cba03d602ce9003a258becf98725f96 Mon Sep 17 00:00:00 2001 From: Darren Shepherd Date: Wed, 9 Dec 2015 12:39:31 -0700 Subject: [PATCH 1/2] Lazy initialize Volume on container Mount object Currently on daemon start volumes are "created" which involves invoking a volume driver if needed. If this process fails the mount is left in a bad state in which there is no source or Volume set. This now becomes an unrecoverable state in which that container can not be started. The only way to fix is to restart the daemon and hopefully you don't get another error on startup. This change moves "createVolume" to be done at container start. If the start fails it leaves it in the state in which you can try another start. If the second start can contact the volume driver everything will recover fine. Signed-off-by: Darren Shepherd Upstream-commit: 2aa673aed7cd10497d578a14a9550c75789e0a43 Component: engine --- components/engine/daemon/daemon.go | 4 ---- components/engine/daemon/mounts.go | 14 -------------- components/engine/daemon/volumes_unix.go | 8 ++++++++ components/engine/daemon/volumes_windows.go | 8 ++++++++ 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go index bbecc677f4..c48a16fa5d 100644 --- a/components/engine/daemon/daemon.go +++ b/components/engine/daemon/daemon.go @@ -283,10 +283,6 @@ func (daemon *Daemon) Register(container *container.Container) error { } } - if err := daemon.prepareMountPoints(container); err != nil { - return err - } - return nil } diff --git a/components/engine/daemon/mounts.go b/components/engine/daemon/mounts.go index 4f3669d37c..c2976d443c 100644 --- a/components/engine/daemon/mounts.go +++ b/components/engine/daemon/mounts.go @@ -8,20 +8,6 @@ import ( volumestore "github.com/docker/docker/volume/store" ) -func (daemon *Daemon) prepareMountPoints(container *container.Container) error { - for _, config := range container.MountPoints { - if len(config.Driver) > 0 { - v, err := daemon.volumes.GetWithRef(config.Name, config.Driver, container.ID) - if err != nil { - return err - } - - config.Volume = v - } - } - return nil -} - func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool) error { var rmErrors []string for _, m := range container.MountPoints { diff --git a/components/engine/daemon/volumes_unix.go b/components/engine/daemon/volumes_unix.go index ea19953093..09c7ae1071 100644 --- a/components/engine/daemon/volumes_unix.go +++ b/components/engine/daemon/volumes_unix.go @@ -20,6 +20,14 @@ import ( func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) { var mounts []execdriver.Mount for _, m := range container.MountPoints { + // Lazy initialize m.Volume if needed. This happens after a daemon restart + if len(m.Driver) > 0 && m.Volume == nil { + v, err := daemon.createVolume(m.Name, m.Driver, nil) + if err != nil { + return nil, err + } + m.Volume = v + } path, err := m.Setup() if err != nil { return nil, err diff --git a/components/engine/daemon/volumes_windows.go b/components/engine/daemon/volumes_windows.go index dd4a9c9f2c..1efbc0e457 100644 --- a/components/engine/daemon/volumes_windows.go +++ b/components/engine/daemon/volumes_windows.go @@ -18,6 +18,14 @@ import ( func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) { var mnts []execdriver.Mount for _, mount := range container.MountPoints { // type is volume.MountPoint + // Lazy initialize m.Volume if needed. This happens after a daemon restart + if len(m.Driver) > 0 && m.Volume == nil { + v, err := daemon.createVolume(m.Name, m.Driver, nil) + if err != nil { + return nil, err + } + m.Volume = v + } // If there is no source, take it from the volume path s := mount.Source if s == "" && mount.Volume != nil { From e92314d4dc7742e4e2c005a132b49b79a7f6344b Mon Sep 17 00:00:00 2001 From: David Calavera Date: Tue, 12 Jan 2016 17:18:57 -0500 Subject: [PATCH 2/2] Remove duplicated lazy volume initialization. Signed-off-by: David Calavera Upstream-commit: aab3596397c7b4fceac9061625898b3d2606597d Component: engine --- components/engine/daemon/daemon.go | 4 ++++ components/engine/daemon/mounts.go | 9 +++++++++ components/engine/daemon/volumes.go | 14 ++++++++++++++ components/engine/daemon/volumes_unix.go | 9 ++------- components/engine/daemon/volumes_windows.go | 9 ++------- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/components/engine/daemon/daemon.go b/components/engine/daemon/daemon.go index c48a16fa5d..bbecc677f4 100644 --- a/components/engine/daemon/daemon.go +++ b/components/engine/daemon/daemon.go @@ -283,6 +283,10 @@ func (daemon *Daemon) Register(container *container.Container) error { } } + if err := daemon.prepareMountPoints(container); err != nil { + return err + } + return nil } diff --git a/components/engine/daemon/mounts.go b/components/engine/daemon/mounts.go index c2976d443c..81a82753ec 100644 --- a/components/engine/daemon/mounts.go +++ b/components/engine/daemon/mounts.go @@ -8,6 +8,15 @@ import ( volumestore "github.com/docker/docker/volume/store" ) +func (daemon *Daemon) prepareMountPoints(container *container.Container) error { + for _, config := range container.MountPoints { + if err := daemon.lazyInitializeVolume(container.ID, config); err != nil { + return err + } + } + return nil +} + func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool) error { var rmErrors []string for _, m := range container.MountPoints { diff --git a/components/engine/daemon/volumes.go b/components/engine/daemon/volumes.go index a7b648a56f..c0097679f6 100644 --- a/components/engine/daemon/volumes.go +++ b/components/engine/daemon/volumes.go @@ -153,3 +153,17 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo return nil } + +// lazyInitializeVolume initializes a mountpoint's volume if needed. +// This happens after a daemon restart. +func (daemon *Daemon) lazyInitializeVolume(containerID string, m *volume.MountPoint) error { + if len(m.Driver) > 0 && m.Volume == nil { + v, err := daemon.volumes.GetWithRef(m.Name, m.Driver, containerID) + + if err != nil { + return err + } + m.Volume = v + } + return nil +} diff --git a/components/engine/daemon/volumes_unix.go b/components/engine/daemon/volumes_unix.go index 09c7ae1071..f257da770c 100644 --- a/components/engine/daemon/volumes_unix.go +++ b/components/engine/daemon/volumes_unix.go @@ -20,13 +20,8 @@ import ( func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) { var mounts []execdriver.Mount for _, m := range container.MountPoints { - // Lazy initialize m.Volume if needed. This happens after a daemon restart - if len(m.Driver) > 0 && m.Volume == nil { - v, err := daemon.createVolume(m.Name, m.Driver, nil) - if err != nil { - return nil, err - } - m.Volume = v + if err := daemon.lazyInitializeVolume(container.ID, m); err != nil { + return nil, err } path, err := m.Setup() if err != nil { diff --git a/components/engine/daemon/volumes_windows.go b/components/engine/daemon/volumes_windows.go index 1efbc0e457..05a45c385d 100644 --- a/components/engine/daemon/volumes_windows.go +++ b/components/engine/daemon/volumes_windows.go @@ -18,13 +18,8 @@ import ( func (daemon *Daemon) setupMounts(container *container.Container) ([]execdriver.Mount, error) { var mnts []execdriver.Mount for _, mount := range container.MountPoints { // type is volume.MountPoint - // Lazy initialize m.Volume if needed. This happens after a daemon restart - if len(m.Driver) > 0 && m.Volume == nil { - v, err := daemon.createVolume(m.Name, m.Driver, nil) - if err != nil { - return nil, err - } - m.Volume = v + if err := daemon.lazyInitializeVolume(container.ID, mount); err != nil { + return nil, err } // If there is no source, take it from the volume path s := mount.Source