PageRenderTime 76ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/daemon/cluster/volumes.go

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