diff options
author | Sebastiaan van Stijn <github@gone.nl> | 2021-02-15 18:45:15 +0100 |
---|---|---|
committer | Sebastiaan van Stijn <github@gone.nl> | 2021-05-05 16:02:22 +0200 |
commit | e5ae83e503e81baec32f71ae5e775d414ba76ded (patch) | |
tree | d13cba18cea9b8480b33989538ff78abbf299c01 /volume | |
parent | 892d3d57be0f78ce3f11b247b1063cdce9f6472d (diff) | |
download | docker-e5ae83e503e81baec32f71ae5e775d414ba76ded.tar.gz |
volumes: only send "create" event when actually creating volume
The VolumesService did not have information wether or not a volume
was _created_ or if a volume already existed in the driver, and
the existing volume was used.
As a result, multiple "create" events could be generated for the
same volume. For example:
1. Run `docker events` in a shell to start listening for events
2. Create a volume:
docker volume create myvolume
3. Start a container that uses that volume:
docker run -dit -v myvolume:/foo busybox
4. Check the events that were generated:
2021-02-15T18:49:55.874621004+01:00 volume create myvolume (driver=local)
2021-02-15T18:50:11.442759052+01:00 volume create myvolume (driver=local)
2021-02-15T18:50:11.487104176+01:00 container create 45112157c8b1382626bf5e01ef18445a4c680f3846c5e32d01775dddee8ca6d1 (image=busybox, name=gracious_hypatia)
2021-02-15T18:50:11.519288102+01:00 network connect a19f6bb8d44ff84d478670fa4e34c5bf5305f42786294d3d90e790ac74b6d3e0 (container=45112157c8b1382626bf5e01ef18445a4c680f3846c5e32d01775dddee8ca6d1, name=bridge, type=bridge)
2021-02-15T18:50:11.526407799+01:00 volume mount myvolume (container=45112157c8b1382626bf5e01ef18445a4c680f3846c5e32d01775dddee8ca6d1, destination=/foo, driver=local, propagation=, read/write=true)
2021-02-15T18:50:11.864134043+01:00 container start 45112157c8b1382626bf5e01ef18445a4c680f3846c5e32d01775dddee8ca6d1 (image=busybox, name=gracious_hypatia)
5. Notice that a "volume create" event is created twice;
- once when `docker volume create` was ran
- once when `docker run ...` was ran
This patch moves the generation of (most) events to the volume _store_, and only
generates an event if the volume did not yet exist.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Diffstat (limited to 'volume')
-rw-r--r-- | volume/service/service.go | 15 | ||||
-rw-r--r-- | volume/service/store.go | 49 |
2 files changed, 43 insertions, 21 deletions
diff --git a/volume/service/service.go b/volume/service/service.go index b185471a39..3dcd9b336c 100644 --- a/volume/service/service.go +++ b/volume/service/service.go @@ -23,7 +23,9 @@ type ds interface { GetDriverList() []string } -type volumeEventLogger interface { +// VolumeEventLogger interface provides methods to log volume-related events +type VolumeEventLogger interface { + // LogVolumeEvent generates an event related to a volume. LogVolumeEvent(volumeID, action string, attributes map[string]string) } @@ -33,17 +35,17 @@ type VolumesService struct { vs *VolumeStore ds ds pruneRunning int32 - eventLogger volumeEventLogger + eventLogger VolumeEventLogger } // NewVolumeService creates a new volume service -func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) { +func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger VolumeEventLogger) (*VolumesService, error) { ds := drivers.NewStore(pg) if err := setupDefaultDriver(ds, root, rootIDs); err != nil { return nil, err } - vs, err := NewStore(root, ds) + vs, err := NewStore(root, ds, WithEventLogger(logger)) if err != nil { return nil, err } @@ -71,7 +73,6 @@ func (s *VolumesService) Create(ctx context.Context, name, driverName string, op return nil, err } - s.eventLogger.LogVolumeEvent(v.Name(), "create", map[string]string{"driver": v.DriverName()}) apiV := volumeToAPIType(v) return &apiV, nil } @@ -161,10 +162,6 @@ func (s *VolumesService) Remove(ctx context.Context, name string, rmOpts ...opts } else if IsNotExist(err) && cfg.PurgeOnError { err = nil } - - if err == nil { - s.eventLogger.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) - } return err } diff --git a/volume/service/store.go b/volume/service/store.go index 7989f8ddf5..cb88845408 100644 --- a/volume/service/store.go +++ b/volume/service/store.go @@ -68,8 +68,11 @@ func (v volumeWrapper) CachedPath() string { return v.Volume.Path() } +// StoreOpt sets options for a VolumeStore +type StoreOpt func(store *VolumeStore) error + // NewStore creates a new volume store at the given path -func NewStore(rootPath string, drivers *drivers.Store) (*VolumeStore, error) { +func NewStore(rootPath string, drivers *drivers.Store, opts ...StoreOpt) (*VolumeStore, error) { vs := &VolumeStore{ locks: &locker.Locker{}, names: make(map[string]volume.Volume), @@ -79,6 +82,12 @@ func NewStore(rootPath string, drivers *drivers.Store) (*VolumeStore, error) { drivers: drivers, } + for _, o := range opts { + if err := o(vs); err != nil { + return nil, err + } + } + if rootPath != "" { // initialize metadata store volPath := filepath.Join(rootPath, volumeDataDir) @@ -108,6 +117,14 @@ func NewStore(rootPath string, drivers *drivers.Store) (*VolumeStore, error) { return vs, nil } +// WithEventLogger configures the VolumeStore with the given VolumeEventLogger +func WithEventLogger(logger VolumeEventLogger) StoreOpt { + return func(store *VolumeStore) error { + store.eventLogger = logger + return nil + } +} + func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { s.globalLock.RLock() v, exists := s.names[name] @@ -198,7 +215,9 @@ type VolumeStore struct { labels map[string]map[string]string // options stores volume options for each volume options map[string]map[string]string - db *bolt.DB + + db *bolt.DB + eventLogger VolumeEventLogger } func filterByDriver(names []string) filterFunc { @@ -464,7 +483,7 @@ func (s *VolumeStore) Create(ctx context.Context, name, driverName string, creat default: } - v, err := s.create(ctx, name, driverName, cfg.Options, cfg.Labels) + v, created, err := s.create(ctx, name, driverName, cfg.Options, cfg.Labels) if err != nil { if _, ok := err.(*OpErr); ok { return nil, err @@ -472,6 +491,9 @@ func (s *VolumeStore) Create(ctx context.Context, name, driverName string, creat return nil, &OpErr{Err: err, Name: name, Op: "create"} } + if created && s.eventLogger != nil { + s.eventLogger.LogVolumeEvent(v.Name(), "create", map[string]string{"driver": v.DriverName()}) + } s.setNamed(v, cfg.Reference) return v, nil } @@ -552,7 +574,7 @@ func volumeExists(ctx context.Context, store *drivers.Store, v volume.Volume) (b // for the given volume name, an error is returned after checking if the reference is stale. // If the reference is stale, it will be purged and this create can continue. // It is expected that callers of this function hold any necessary locks. -func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, labels map[string]string) (volume.Volume, error) { +func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, labels map[string]string) (volume.Volume, bool, error) { // Validate the name in a platform-specific manner // volume name validation is specific to the host os and not on container image @@ -560,19 +582,19 @@ func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, parser := volumemounts.NewParser(runtime.GOOS) err := parser.ValidateVolumeName(name) if err != nil { - return nil, err + return nil, false, err } v, err := s.checkConflict(ctx, name, driverName) if err != nil { - return nil, err + return nil, false, err } if v != nil { // there is an existing volume, if we already have this stored locally, return it. // TODO: there could be some inconsistent details such as labels here if vv, _ := s.getNamed(v.Name()); vv != nil { - return vv, nil + return vv, false, nil } } @@ -580,7 +602,7 @@ func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, if driverName == "" { v, _ = s.getVolume(ctx, name, "") if v != nil { - return v, nil + return v, false, nil } } @@ -589,7 +611,7 @@ func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, } vd, err := s.drivers.CreateDriver(driverName) if err != nil { - return nil, &OpErr{Op: "create", Name: name, Err: err} + return nil, false, &OpErr{Op: "create", Name: name, Err: err} } logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) @@ -599,7 +621,7 @@ func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, if _, err := s.drivers.ReleaseDriver(driverName); err != nil { logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") } - return nil, err + return nil, false, err } } @@ -617,9 +639,9 @@ func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, } if err := s.setMeta(name, metadata); err != nil { - return nil, err + return nil, true, err } - return volumeWrapper{v, labels, vd.Scope(), opts}, nil + return volumeWrapper{v, labels, vd.Scope(), opts}, true, nil } // Get looks if a volume with the given name exists and returns it if so @@ -802,6 +824,9 @@ func (s *VolumeStore) Remove(ctx context.Context, v volume.Volume, rmOpts ...opt err = e } } + if err == nil && s.eventLogger != nil { + s.eventLogger.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) + } return err } |