github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/volume/service/convert.go (about) 1 package service 2 3 import ( 4 "context" 5 "fmt" 6 "strconv" 7 "time" 8 9 "github.com/docker/docker/api/types/filters" 10 volumetypes "github.com/docker/docker/api/types/volume" 11 "github.com/docker/docker/errdefs" 12 "github.com/docker/docker/pkg/directory" 13 "github.com/docker/docker/volume" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // convertOpts are used to pass options to `volumeToAPI` 18 type convertOpt interface { 19 isConvertOpt() 20 } 21 22 type useCachedPath bool 23 24 func (useCachedPath) isConvertOpt() {} 25 26 type calcSize bool 27 28 func (calcSize) isConvertOpt() {} 29 30 type pathCacher interface { 31 CachedPath() string 32 } 33 34 func (s *VolumesService) volumesToAPI(ctx context.Context, volumes []volume.Volume, opts ...convertOpt) []*volumetypes.Volume { 35 var ( 36 out = make([]*volumetypes.Volume, 0, len(volumes)) 37 getSize bool 38 cachedPath bool 39 ) 40 41 for _, o := range opts { 42 switch t := o.(type) { 43 case calcSize: 44 getSize = bool(t) 45 case useCachedPath: 46 cachedPath = bool(t) 47 } 48 } 49 for _, v := range volumes { 50 select { 51 case <-ctx.Done(): 52 return nil 53 default: 54 } 55 apiV := volumeToAPIType(v) 56 57 if cachedPath { 58 if vv, ok := v.(pathCacher); ok { 59 apiV.Mountpoint = vv.CachedPath() 60 } 61 } else { 62 apiV.Mountpoint = v.Path() 63 } 64 65 if getSize { 66 p := v.Path() 67 if apiV.Mountpoint == "" { 68 apiV.Mountpoint = p 69 } 70 sz, err := directory.Size(ctx, p) 71 if err != nil { 72 logrus.WithError(err).WithField("volume", v.Name()).Warnf("Failed to determine size of volume") 73 sz = -1 74 } 75 apiV.UsageData = &volumetypes.UsageData{Size: sz, RefCount: int64(s.vs.CountReferences(v))} 76 } 77 78 out = append(out, &apiV) 79 } 80 return out 81 } 82 83 func volumeToAPIType(v volume.Volume) volumetypes.Volume { 84 createdAt, _ := v.CreatedAt() 85 tv := volumetypes.Volume{ 86 Name: v.Name(), 87 Driver: v.DriverName(), 88 CreatedAt: createdAt.Format(time.RFC3339), 89 } 90 if v, ok := v.(volume.DetailedVolume); ok { 91 tv.Labels = v.Labels() 92 tv.Options = v.Options() 93 tv.Scope = v.Scope() 94 } 95 if cp, ok := v.(pathCacher); ok { 96 tv.Mountpoint = cp.CachedPath() 97 } 98 return tv 99 } 100 101 func filtersToBy(filter filters.Args, acceptedFilters map[string]bool) (By, error) { 102 if err := filter.Validate(acceptedFilters); err != nil { 103 return nil, err 104 } 105 var bys []By 106 if drivers := filter.Get("driver"); len(drivers) > 0 { 107 bys = append(bys, ByDriver(drivers...)) 108 } 109 if filter.Contains("name") { 110 bys = append(bys, CustomFilter(func(v volume.Volume) bool { 111 return filter.Match("name", v.Name()) 112 })) 113 } 114 bys = append(bys, byLabelFilter(filter)) 115 116 if filter.Contains("dangling") { 117 var dangling bool 118 if filter.ExactMatch("dangling", "true") || filter.ExactMatch("dangling", "1") { 119 dangling = true 120 } else if !filter.ExactMatch("dangling", "false") && !filter.ExactMatch("dangling", "0") { 121 return nil, invalidFilter{"dangling", filter.Get("dangling")} 122 } 123 bys = append(bys, ByReferenced(!dangling)) 124 } 125 126 var by By 127 switch len(bys) { 128 case 0: 129 case 1: 130 by = bys[0] 131 default: 132 by = And(bys...) 133 } 134 return by, nil 135 } 136 137 func withPrune(filter filters.Args) error { 138 all := filter.Get("all") 139 switch { 140 case len(all) > 1: 141 return invalidFilter{"all", all} 142 case len(all) == 1: 143 ok, err := strconv.ParseBool(all[0]) 144 if err != nil { 145 return errdefs.InvalidParameter(fmt.Errorf("invalid filter 'all': %w", err)) 146 } 147 if ok { 148 return nil 149 } 150 } 151 152 filter.Add("label", AnonymousLabel) 153 return nil 154 }