github.com/zhouyu0/docker-note@v0.0.0-20190722021225-b8d3825084db/volume/service/service.go (about) 1 package service // import "github.com/docker/docker/volume/service" 2 3 import ( 4 "context" 5 "sync/atomic" 6 7 "github.com/docker/docker/api/types" 8 "github.com/docker/docker/api/types/filters" 9 "github.com/docker/docker/errdefs" 10 "github.com/docker/docker/pkg/directory" 11 "github.com/docker/docker/pkg/idtools" 12 "github.com/docker/docker/pkg/plugingetter" 13 "github.com/docker/docker/pkg/stringid" 14 "github.com/docker/docker/volume" 15 "github.com/docker/docker/volume/drivers" 16 "github.com/docker/docker/volume/service/opts" 17 "github.com/pkg/errors" 18 "github.com/sirupsen/logrus" 19 ) 20 21 type ds interface { 22 GetDriverList() []string 23 } 24 25 type volumeEventLogger interface { 26 LogVolumeEvent(volumeID, action string, attributes map[string]string) 27 } 28 29 // VolumesService manages access to volumes 30 type VolumesService struct { 31 vs *VolumeStore 32 ds ds 33 pruneRunning int32 34 eventLogger volumeEventLogger 35 } 36 37 // NewVolumeService creates a new volume service 38 func NewVolumeService(root string, pg plugingetter.PluginGetter, rootIDs idtools.Identity, logger volumeEventLogger) (*VolumesService, error) { 39 ds := drivers.NewStore(pg) 40 if err := setupDefaultDriver(ds, root, rootIDs); err != nil { 41 return nil, err 42 } 43 44 vs, err := NewStore(root, ds) 45 if err != nil { 46 return nil, err 47 } 48 return &VolumesService{vs: vs, ds: ds, eventLogger: logger}, nil 49 } 50 51 // GetDriverList gets the list of registered volume drivers 52 func (s *VolumesService) GetDriverList() []string { 53 return s.ds.GetDriverList() 54 } 55 56 // Create creates a volume 57 func (s *VolumesService) Create(ctx context.Context, name, driverName string, opts ...opts.CreateOption) (*types.Volume, error) { 58 if name == "" { 59 name = stringid.GenerateRandomID() 60 } 61 v, err := s.vs.Create(ctx, name, driverName, opts...) 62 if err != nil { 63 return nil, err 64 } 65 66 s.eventLogger.LogVolumeEvent(v.Name(), "create", map[string]string{"driver": v.DriverName()}) 67 apiV := volumeToAPIType(v) 68 return &apiV, nil 69 } 70 71 // Get gets a volume 72 func (s *VolumesService) Get(ctx context.Context, name string, getOpts ...opts.GetOption) (*types.Volume, error) { 73 v, err := s.vs.Get(ctx, name, getOpts...) 74 if err != nil { 75 return nil, err 76 } 77 vol := volumeToAPIType(v) 78 79 var cfg opts.GetConfig 80 for _, o := range getOpts { 81 o(&cfg) 82 } 83 84 if cfg.ResolveStatus { 85 vol.Status = v.Status() 86 } 87 return &vol, nil 88 } 89 90 // Mount mounts the volume 91 func (s *VolumesService) Mount(ctx context.Context, vol *types.Volume, ref string) (string, error) { 92 v, err := s.vs.Get(ctx, vol.Name, opts.WithGetDriver(vol.Driver)) 93 if err != nil { 94 if IsNotExist(err) { 95 err = errdefs.NotFound(err) 96 } 97 return "", err 98 } 99 return v.Mount(ref) 100 } 101 102 // Unmount unmounts the volume. 103 // Note that depending on the implementation, the volume may still be mounted due to other resources using it. 104 func (s *VolumesService) Unmount(ctx context.Context, vol *types.Volume, ref string) error { 105 v, err := s.vs.Get(ctx, vol.Name, opts.WithGetDriver(vol.Driver)) 106 if err != nil { 107 if IsNotExist(err) { 108 err = errdefs.NotFound(err) 109 } 110 return err 111 } 112 return v.Unmount(ref) 113 } 114 115 // Release releases a volume reference 116 func (s *VolumesService) Release(ctx context.Context, name string, ref string) error { 117 return s.vs.Release(ctx, name, ref) 118 } 119 120 // Remove removes a volume 121 func (s *VolumesService) Remove(ctx context.Context, name string, rmOpts ...opts.RemoveOption) error { 122 var cfg opts.RemoveConfig 123 for _, o := range rmOpts { 124 o(&cfg) 125 } 126 127 v, err := s.vs.Get(ctx, name) 128 if err != nil { 129 if IsNotExist(err) && cfg.PurgeOnError { 130 return nil 131 } 132 return err 133 } 134 135 err = s.vs.Remove(ctx, v, rmOpts...) 136 if IsNotExist(err) { 137 err = nil 138 } else if IsInUse(err) { 139 err = errdefs.Conflict(err) 140 } else if IsNotExist(err) && cfg.PurgeOnError { 141 err = nil 142 } 143 144 if err == nil { 145 s.eventLogger.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) 146 } 147 return err 148 } 149 150 var acceptedPruneFilters = map[string]bool{ 151 "label": true, 152 "label!": true, 153 } 154 155 var acceptedListFilters = map[string]bool{ 156 "dangling": true, 157 "name": true, 158 "driver": true, 159 "label": true, 160 } 161 162 // LocalVolumesSize gets all local volumes and fetches their size on disk 163 // Note that this intentionally skips volumes which have mount options. Typically 164 // volumes with mount options are not really local even if they are using the 165 // local driver. 166 func (s *VolumesService) LocalVolumesSize(ctx context.Context) ([]*types.Volume, error) { 167 ls, _, err := s.vs.Find(ctx, And(ByDriver(volume.DefaultDriverName), CustomFilter(func(v volume.Volume) bool { 168 dv, ok := v.(volume.DetailedVolume) 169 return ok && len(dv.Options()) == 0 170 }))) 171 if err != nil { 172 return nil, err 173 } 174 return s.volumesToAPI(ctx, ls, calcSize(true)), nil 175 } 176 177 // Prune removes (local) volumes which match the past in filter arguments. 178 // Note that this intentionally skips volumes with mount options as there would 179 // be no space reclaimed in this case. 180 func (s *VolumesService) Prune(ctx context.Context, filter filters.Args) (*types.VolumesPruneReport, error) { 181 if !atomic.CompareAndSwapInt32(&s.pruneRunning, 0, 1) { 182 return nil, errdefs.Conflict(errors.New("a prune operation is already running")) 183 } 184 defer atomic.StoreInt32(&s.pruneRunning, 0) 185 186 by, err := filtersToBy(filter, acceptedPruneFilters) 187 if err != nil { 188 return nil, err 189 } 190 ls, _, err := s.vs.Find(ctx, And(ByDriver(volume.DefaultDriverName), ByReferenced(false), by, CustomFilter(func(v volume.Volume) bool { 191 dv, ok := v.(volume.DetailedVolume) 192 return ok && len(dv.Options()) == 0 193 }))) 194 if err != nil { 195 return nil, err 196 } 197 198 rep := &types.VolumesPruneReport{VolumesDeleted: make([]string, 0, len(ls))} 199 for _, v := range ls { 200 select { 201 case <-ctx.Done(): 202 err := ctx.Err() 203 if err == context.Canceled { 204 err = nil 205 } 206 return rep, err 207 default: 208 } 209 210 vSize, err := directory.Size(ctx, v.Path()) 211 if err != nil { 212 logrus.WithField("volume", v.Name()).WithError(err).Warn("could not determine size of volume") 213 } 214 if err := s.vs.Remove(ctx, v); err != nil { 215 logrus.WithError(err).WithField("volume", v.Name()).Warnf("Could not determine size of volume") 216 continue 217 } 218 rep.SpaceReclaimed += uint64(vSize) 219 rep.VolumesDeleted = append(rep.VolumesDeleted, v.Name()) 220 } 221 return rep, nil 222 } 223 224 // List gets the list of volumes which match the past in filters 225 // If filters is nil or empty all volumes are returned. 226 func (s *VolumesService) List(ctx context.Context, filter filters.Args) (volumesOut []*types.Volume, warnings []string, err error) { 227 by, err := filtersToBy(filter, acceptedListFilters) 228 if err != nil { 229 return nil, nil, err 230 } 231 232 volumes, warnings, err := s.vs.Find(ctx, by) 233 if err != nil { 234 return nil, nil, err 235 } 236 237 return s.volumesToAPI(ctx, volumes, useCachedPath(true)), warnings, nil 238 } 239 240 // Shutdown shuts down the image service and dependencies 241 func (s *VolumesService) Shutdown() error { 242 return s.vs.Shutdown() 243 }