github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/varlinkapi/volumes.go (about)

     1  // +build varlink
     2  
     3  package varlinkapi
     4  
     5  import (
     6  	"context"
     7  	"encoding/json"
     8  
     9  	"github.com/containers/podman/v2/libpod"
    10  	"github.com/containers/podman/v2/pkg/domain/infra/abi/parse"
    11  	iopodman "github.com/containers/podman/v2/pkg/varlink"
    12  )
    13  
    14  // VolumeCreate creates a libpod volume based on input from a varlink connection
    15  func (i *VarlinkAPI) VolumeCreate(call iopodman.VarlinkCall, options iopodman.VolumeCreateOpts) error {
    16  	var volumeOptions []libpod.VolumeCreateOption
    17  
    18  	if len(options.VolumeName) > 0 {
    19  		volumeOptions = append(volumeOptions, libpod.WithVolumeName(options.VolumeName))
    20  	}
    21  	if len(options.Driver) > 0 {
    22  		volumeOptions = append(volumeOptions, libpod.WithVolumeDriver(options.Driver))
    23  	}
    24  	if len(options.Labels) > 0 {
    25  		volumeOptions = append(volumeOptions, libpod.WithVolumeLabels(options.Labels))
    26  	}
    27  	if len(options.Options) > 0 {
    28  		parsedOptions, err := parse.VolumeOptions(options.Options)
    29  		if err != nil {
    30  			return call.ReplyErrorOccurred(err.Error())
    31  		}
    32  		volumeOptions = append(volumeOptions, parsedOptions...)
    33  	}
    34  	newVolume, err := i.Runtime.NewVolume(getContext(), volumeOptions...)
    35  	if err != nil {
    36  		return call.ReplyErrorOccurred(err.Error())
    37  	}
    38  	return call.ReplyVolumeCreate(newVolume.Name())
    39  }
    40  
    41  // VolumeRemove removes volumes by options.All or options.Volumes
    42  func (i *VarlinkAPI) VolumeRemove(call iopodman.VarlinkCall, options iopodman.VolumeRemoveOpts) error {
    43  	success, failed, err := SharedRemoveVolumes(getContext(), i.Runtime, options.Volumes, options.All, options.Force)
    44  	if err != nil {
    45  		return call.ReplyErrorOccurred(err.Error())
    46  	}
    47  	// Convert map[string]string to map[string]error
    48  	errStrings := make(map[string]string)
    49  	for k, v := range failed {
    50  		errStrings[k] = v.Error()
    51  	}
    52  	return call.ReplyVolumeRemove(success, errStrings)
    53  }
    54  
    55  // GetVolumes returns all the volumes known to the remote system
    56  func (i *VarlinkAPI) GetVolumes(call iopodman.VarlinkCall, args []string, all bool) error {
    57  	var (
    58  		err     error
    59  		reply   []*libpod.Volume
    60  		volumes []iopodman.Volume
    61  	)
    62  	if all {
    63  		reply, err = i.Runtime.GetAllVolumes()
    64  	} else {
    65  		for _, v := range args {
    66  			vol, err := i.Runtime.GetVolume(v)
    67  			if err != nil {
    68  				return err
    69  			}
    70  			reply = append(reply, vol)
    71  		}
    72  	}
    73  	if err != nil {
    74  		return call.ReplyErrorOccurred(err.Error())
    75  	}
    76  	// Build the iopodman.volume struct for the return
    77  	for _, v := range reply {
    78  		newVol := iopodman.Volume{
    79  			Driver:     v.Driver(),
    80  			Labels:     v.Labels(),
    81  			MountPoint: v.MountPoint(),
    82  			Name:       v.Name(),
    83  			Options:    v.Options(),
    84  		}
    85  		volumes = append(volumes, newVol)
    86  	}
    87  	return call.ReplyGetVolumes(volumes)
    88  }
    89  
    90  // InspectVolume inspects a single volume, returning its JSON as a string.
    91  func (i *VarlinkAPI) InspectVolume(call iopodman.VarlinkCall, name string) error {
    92  	vol, err := i.Runtime.LookupVolume(name)
    93  	if err != nil {
    94  		return call.ReplyErrorOccurred(err.Error())
    95  	}
    96  	inspectOut, err := vol.Inspect()
    97  	if err != nil {
    98  		return call.ReplyErrorOccurred(err.Error())
    99  	}
   100  	inspectJSON, err := json.Marshal(inspectOut)
   101  	if err != nil {
   102  		return call.ReplyErrorOccurred(err.Error())
   103  	}
   104  	return call.ReplyInspectVolume(string(inspectJSON))
   105  }
   106  
   107  // VolumesPrune removes unused images via a varlink call
   108  func (i *VarlinkAPI) VolumesPrune(call iopodman.VarlinkCall) error {
   109  	var (
   110  		prunedErrors []string
   111  		prunedNames  []string
   112  	)
   113  	responses, err := i.Runtime.PruneVolumes(getContext())
   114  	if err != nil {
   115  		return call.ReplyVolumesPrune([]string{}, []string{err.Error()})
   116  	}
   117  	for k, v := range responses {
   118  		if v == nil {
   119  			prunedNames = append(prunedNames, k)
   120  		} else {
   121  			prunedErrors = append(prunedErrors, v.Error())
   122  		}
   123  	}
   124  	return call.ReplyVolumesPrune(prunedNames, prunedErrors)
   125  }
   126  
   127  // Remove given set of volumes
   128  func SharedRemoveVolumes(ctx context.Context, runtime *libpod.Runtime, vols []string, all, force bool) ([]string, map[string]error, error) {
   129  	var (
   130  		toRemove []*libpod.Volume
   131  		success  []string
   132  		failed   map[string]error
   133  	)
   134  
   135  	failed = make(map[string]error)
   136  
   137  	if all {
   138  		vols, err := runtime.Volumes()
   139  		if err != nil {
   140  			return nil, nil, err
   141  		}
   142  		toRemove = vols
   143  	} else {
   144  		for _, v := range vols {
   145  			vol, err := runtime.LookupVolume(v)
   146  			if err != nil {
   147  				failed[v] = err
   148  				continue
   149  			}
   150  			toRemove = append(toRemove, vol)
   151  		}
   152  	}
   153  
   154  	// We could parallelize this, but I haven't heard anyone complain about
   155  	// performance here yet, so hold off.
   156  	for _, vol := range toRemove {
   157  		if err := runtime.RemoveVolume(ctx, vol, force); err != nil {
   158  			failed[vol.Name()] = err
   159  			continue
   160  		}
   161  		success = append(success, vol.Name())
   162  	}
   163  
   164  	return success, failed, nil
   165  }