github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/cluster/volumes.go (about)

     1  package cluster // import "github.com/Prakhar-Agarwal-byte/moby/daemon/cluster"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	volumetypes "github.com/Prakhar-Agarwal-byte/moby/api/types/volume"
     8  	"github.com/Prakhar-Agarwal-byte/moby/daemon/cluster/convert"
     9  	"github.com/Prakhar-Agarwal-byte/moby/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  			if force && errdefs.IsNotFound(err) {
    94  				return nil
    95  			}
    96  			return err
    97  		}
    98  
    99  		req := &swarmapi.RemoveVolumeRequest{
   100  			VolumeID: volume.ID,
   101  			Force:    force,
   102  		}
   103  		_, err = state.controlClient.RemoveVolume(ctx, req)
   104  		return err
   105  	})
   106  }
   107  
   108  // UpdateVolume updates a volume in the swarm cluster.
   109  func (c *Cluster) UpdateVolume(nameOrID string, version uint64, volume volumetypes.UpdateOptions) error {
   110  	return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
   111  		v, err := getVolume(ctx, state.controlClient, nameOrID)
   112  		if err != nil {
   113  			return err
   114  		}
   115  
   116  		// For now, the only thing we can update is availability. Instead of
   117  		// converting the whole spec, just pluck out the availability if it has
   118  		// been set.
   119  
   120  		if volume.Spec != nil {
   121  			switch volume.Spec.Availability {
   122  			case volumetypes.AvailabilityActive:
   123  				v.Spec.Availability = swarmapi.VolumeAvailabilityActive
   124  			case volumetypes.AvailabilityPause:
   125  				v.Spec.Availability = swarmapi.VolumeAvailabilityPause
   126  			case volumetypes.AvailabilityDrain:
   127  				v.Spec.Availability = swarmapi.VolumeAvailabilityDrain
   128  			}
   129  			// if default empty value, change nothing.
   130  		}
   131  
   132  		_, err = state.controlClient.UpdateVolume(
   133  			ctx, &swarmapi.UpdateVolumeRequest{
   134  				VolumeID: nameOrID,
   135  				VolumeVersion: &swarmapi.Version{
   136  					Index: version,
   137  				},
   138  				Spec: &v.Spec,
   139  			},
   140  		)
   141  		return err
   142  	})
   143  }