github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/daemon/cluster/volumes.go (about)

     1  package cluster // import "github.com/docker/docker/daemon/cluster"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	volumetypes "github.com/docker/docker/api/types/volume"
     8  	"github.com/docker/docker/daemon/cluster/convert"
     9  	"github.com/docker/docker/errdefs"
    10  	swarmapi "github.com/moby/swarmkit/v2/api"
    11  	"google.golang.org/grpc"
    12  )
    13  
    14  // GetVolume returns a volume from the swarm cluster.
    15  func (c *Cluster) GetVolume(nameOrID string) (volumetypes.Volume, error) {
    16  	var volume *swarmapi.Volume
    17  
    18  	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
    19  		v, err := getVolume(ctx, state.controlClient, nameOrID)
    20  		if err != nil {
    21  			return err
    22  		}
    23  		volume = v
    24  		return nil
    25  	}); err != nil {
    26  		return volumetypes.Volume{}, err
    27  	}
    28  	return convert.VolumeFromGRPC(volume), nil
    29  }
    30  
    31  // GetVolumes returns all of the volumes matching the given options from a swarm cluster.
    32  func (c *Cluster) GetVolumes(options volumetypes.ListOptions) ([]*volumetypes.Volume, error) {
    33  	var volumes []*volumetypes.Volume
    34  	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
    35  		r, err := state.controlClient.ListVolumes(
    36  			ctx, &swarmapi.ListVolumesRequest{},
    37  			grpc.MaxCallRecvMsgSize(defaultRecvSizeForListResponse),
    38  		)
    39  		if err != nil {
    40  			return err
    41  		}
    42  
    43  		volumes = make([]*volumetypes.Volume, 0, len(r.Volumes))
    44  		for _, volume := range r.Volumes {
    45  			v := convert.VolumeFromGRPC(volume)
    46  			volumes = append(volumes, &v)
    47  		}
    48  
    49  		return nil
    50  	}); err != nil {
    51  		return nil, err
    52  	}
    53  
    54  	return volumes, nil
    55  }
    56  
    57  // CreateVolume creates a new cluster volume in the swarm cluster.
    58  //
    59  // Returns the volume ID if creation is successful, or an error if not.
    60  func (c *Cluster) CreateVolume(v volumetypes.CreateOptions) (*volumetypes.Volume, error) {
    61  	var resp *swarmapi.CreateVolumeResponse
    62  	if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
    63  		volumeSpec := convert.VolumeCreateToGRPC(&v)
    64  
    65  		r, err := state.controlClient.CreateVolume(
    66  			ctx, &swarmapi.CreateVolumeRequest{Spec: volumeSpec},
    67  		)
    68  		if err != nil {
    69  			return err
    70  		}
    71  		resp = r
    72  		return nil
    73  	}); err != nil {
    74  		return nil, err
    75  	}
    76  	createdVol, err := c.GetVolume(resp.Volume.ID)
    77  	if err != nil {
    78  		// If there's a failure of some sort in this operation the user would
    79  		// get a very unhelpful "not found" error on a create, which is not
    80  		// very helpful at all. Instead, before returning the error, add some
    81  		// context, and change this to a system-type error, because it's
    82  		// nothing the user did wrong.
    83  		return nil, errdefs.System(fmt.Errorf("unable to retrieve created volume: %w", err))
    84  	}
    85  	return &createdVol, nil
    86  }
    87  
    88  // RemoveVolume removes a volume from the swarm cluster.
    89  func (c *Cluster) RemoveVolume(nameOrID string, force bool) error {
    90  	return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
    91  		volume, err := getVolume(ctx, state.controlClient, nameOrID)
    92  		if err != nil {
    93  			return err
    94  		}
    95  
    96  		req := &swarmapi.RemoveVolumeRequest{
    97  			VolumeID: volume.ID,
    98  			Force:    force,
    99  		}
   100  		_, err = state.controlClient.RemoveVolume(ctx, req)
   101  		return err
   102  	})
   103  }
   104  
   105  // UpdateVolume updates a volume in the swarm cluster.
   106  func (c *Cluster) UpdateVolume(nameOrID string, version uint64, volume volumetypes.UpdateOptions) error {
   107  	return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
   108  		v, err := getVolume(ctx, state.controlClient, nameOrID)
   109  		if err != nil {
   110  			return err
   111  		}
   112  
   113  		// For now, the only thing we can update is availability. Instead of
   114  		// converting the whole spec, just pluck out the availability if it has
   115  		// been set.
   116  
   117  		if volume.Spec != nil {
   118  			switch volume.Spec.Availability {
   119  			case volumetypes.AvailabilityActive:
   120  				v.Spec.Availability = swarmapi.VolumeAvailabilityActive
   121  			case volumetypes.AvailabilityPause:
   122  				v.Spec.Availability = swarmapi.VolumeAvailabilityPause
   123  			case volumetypes.AvailabilityDrain:
   124  				v.Spec.Availability = swarmapi.VolumeAvailabilityDrain
   125  			}
   126  			// if default empty value, change nothing.
   127  		}
   128  
   129  		_, err = state.controlClient.UpdateVolume(
   130  			ctx, &swarmapi.UpdateVolumeRequest{
   131  				VolumeID: nameOrID,
   132  				VolumeVersion: &swarmapi.Version{
   133  					Index: version,
   134  				},
   135  				Spec: &v.Spec,
   136  			},
   137  		)
   138  		return err
   139  	})
   140  }