/daemon/cluster/volumes.go
Go | 140 lines | 108 code | 16 blank | 16 comment | 22 complexity | 8436cff8d68871df6aafe6011f57805a MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-2-Clause, CC-BY-4.0, 0BSD, CC-BY-SA-4.0, GPL-2.0, BSD-3-Clause, MIT
- package cluster // import "github.com/docker/docker/daemon/cluster"
- import (
- "context"
- "fmt"
- volumetypes "github.com/docker/docker/api/types/volume"
- "github.com/docker/docker/daemon/cluster/convert"
- "github.com/docker/docker/errdefs"
- swarmapi "github.com/moby/swarmkit/v2/api"
- "google.golang.org/grpc"
- )
- // GetVolume returns a volume from the swarm cluster.
- func (c *Cluster) GetVolume(nameOrID string) (volumetypes.Volume, error) {
- var volume *swarmapi.Volume
- if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
- v, err := getVolume(ctx, state.controlClient, nameOrID)
- if err != nil {
- return err
- }
- volume = v
- return nil
- }); err != nil {
- return volumetypes.Volume{}, err
- }
- return convert.VolumeFromGRPC(volume), nil
- }
- // GetVolumes returns all of the volumes matching the given options from a swarm cluster.
- func (c *Cluster) GetVolumes(options volumetypes.ListOptions) ([]*volumetypes.Volume, error) {
- var volumes []*volumetypes.Volume
- if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
- r, err := state.controlClient.ListVolumes(
- ctx, &swarmapi.ListVolumesRequest{},
- grpc.MaxCallRecvMsgSize(defaultRecvSizeForListResponse),
- )
- if err != nil {
- return err
- }
- volumes = make([]*volumetypes.Volume, 0, len(r.Volumes))
- for _, volume := range r.Volumes {
- v := convert.VolumeFromGRPC(volume)
- volumes = append(volumes, &v)
- }
- return nil
- }); err != nil {
- return nil, err
- }
- return volumes, nil
- }
- // CreateVolume creates a new cluster volume in the swarm cluster.
- //
- // Returns the volume ID if creation is successful, or an error if not.
- func (c *Cluster) CreateVolume(v volumetypes.CreateOptions) (*volumetypes.Volume, error) {
- var resp *swarmapi.CreateVolumeResponse
- if err := c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
- volumeSpec := convert.VolumeCreateToGRPC(&v)
- r, err := state.controlClient.CreateVolume(
- ctx, &swarmapi.CreateVolumeRequest{Spec: volumeSpec},
- )
- if err != nil {
- return err
- }
- resp = r
- return nil
- }); err != nil {
- return nil, err
- }
- createdVol, err := c.GetVolume(resp.Volume.ID)
- if err != nil {
- // If there's a failure of some sort in this operation the user would
- // get a very unhelpful "not found" error on a create, which is not
- // very helpful at all. Instead, before returning the error, add some
- // context, and change this to a system-type error, because it's
- // nothing the user did wrong.
- return nil, errdefs.System(fmt.Errorf("unable to retrieve created volume: %w", err))
- }
- return &createdVol, nil
- }
- // RemoveVolume removes a volume from the swarm cluster.
- func (c *Cluster) RemoveVolume(nameOrID string, force bool) error {
- return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
- volume, err := getVolume(ctx, state.controlClient, nameOrID)
- if err != nil {
- return err
- }
- req := &swarmapi.RemoveVolumeRequest{
- VolumeID: volume.ID,
- Force: force,
- }
- _, err = state.controlClient.RemoveVolume(ctx, req)
- return err
- })
- }
- // UpdateVolume updates a volume in the swarm cluster.
- func (c *Cluster) UpdateVolume(nameOrID string, version uint64, volume volumetypes.UpdateOptions) error {
- return c.lockedManagerAction(func(ctx context.Context, state nodeState) error {
- v, err := getVolume(ctx, state.controlClient, nameOrID)
- if err != nil {
- return err
- }
- // For now, the only thing we can update is availability. Instead of
- // converting the whole spec, just pluck out the availability if it has
- // been set.
- if volume.Spec != nil {
- switch volume.Spec.Availability {
- case volumetypes.AvailabilityActive:
- v.Spec.Availability = swarmapi.VolumeAvailabilityActive
- case volumetypes.AvailabilityPause:
- v.Spec.Availability = swarmapi.VolumeAvailabilityPause
- case volumetypes.AvailabilityDrain:
- v.Spec.Availability = swarmapi.VolumeAvailabilityDrain
- }
- // if default empty value, change nothing.
- }
- _, err = state.controlClient.UpdateVolume(
- ctx, &swarmapi.UpdateVolumeRequest{
- VolumeID: nameOrID,
- VolumeVersion: &swarmapi.Version{
- Index: version,
- },
- Spec: &v.Spec,
- },
- )
- return err
- })
- }