github.com/moby/docker@v26.1.3+incompatible/volume/service/convert.go (about)

     1  package service
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  	"time"
     8  
     9  	"github.com/containerd/log"
    10  	"github.com/docker/docker/api/types/filters"
    11  	volumetypes "github.com/docker/docker/api/types/volume"
    12  	"github.com/docker/docker/errdefs"
    13  	"github.com/docker/docker/pkg/directory"
    14  	"github.com/docker/docker/volume"
    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  				log.G(ctx).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  		dangling, err := filter.GetBoolOrDefault("dangling", false)
   118  		if err != nil {
   119  			return nil, err
   120  		}
   121  		bys = append(bys, ByReferenced(!dangling))
   122  	}
   123  
   124  	var by By
   125  	switch len(bys) {
   126  	case 0:
   127  	case 1:
   128  		by = bys[0]
   129  	default:
   130  		by = And(bys...)
   131  	}
   132  	return by, nil
   133  }
   134  
   135  func withPrune(filter filters.Args) error {
   136  	all := filter.Get("all")
   137  	switch {
   138  	case len(all) > 1:
   139  		return errdefs.InvalidParameter(fmt.Errorf("invalid filter 'all=%s': only one value is expected", all))
   140  	case len(all) == 1:
   141  		ok, err := strconv.ParseBool(all[0])
   142  		if err != nil {
   143  			return errdefs.InvalidParameter(fmt.Errorf("invalid filter 'all': %w", err))
   144  		}
   145  		if ok {
   146  			return nil
   147  		}
   148  	}
   149  
   150  	filter.Add("label", AnonymousLabel)
   151  	return nil
   152  }