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 }