github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/api/server/router/volume/volume_routes_test.go (about)

     1  package volume
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http/httptest"
     9  	"testing"
    10  
    11  	"gotest.tools/v3/assert"
    12  
    13  	"github.com/docker/docker/api/server/httputils"
    14  	"github.com/docker/docker/api/types"
    15  	"github.com/docker/docker/api/types/filters"
    16  	"github.com/docker/docker/api/types/volume"
    17  	"github.com/docker/docker/errdefs"
    18  	"github.com/docker/docker/volume/service/opts"
    19  )
    20  
    21  func callGetVolume(v *volumeRouter, name string) (*httptest.ResponseRecorder, error) {
    22  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
    23  	vars := map[string]string{"name": name}
    24  	req := httptest.NewRequest("GET", fmt.Sprintf("/volumes/%s", name), nil)
    25  	resp := httptest.NewRecorder()
    26  
    27  	err := v.getVolumeByName(ctx, resp, req, vars)
    28  	return resp, err
    29  }
    30  
    31  func callListVolumes(v *volumeRouter) (*httptest.ResponseRecorder, error) {
    32  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
    33  	vars := map[string]string{}
    34  	req := httptest.NewRequest("GET", "/volumes", nil)
    35  	resp := httptest.NewRecorder()
    36  
    37  	err := v.getVolumesList(ctx, resp, req, vars)
    38  	return resp, err
    39  }
    40  
    41  func TestGetVolumeByNameNotFoundNoSwarm(t *testing.T) {
    42  	v := &volumeRouter{
    43  		backend: &fakeVolumeBackend{},
    44  		cluster: &fakeClusterBackend{},
    45  	}
    46  
    47  	_, err := callGetVolume(v, "notReal")
    48  
    49  	assert.Assert(t, err != nil)
    50  	assert.Assert(t, errdefs.IsNotFound(err))
    51  }
    52  
    53  func TestGetVolumeByNameNotFoundNotManager(t *testing.T) {
    54  	v := &volumeRouter{
    55  		backend: &fakeVolumeBackend{},
    56  		cluster: &fakeClusterBackend{swarm: true},
    57  	}
    58  
    59  	_, err := callGetVolume(v, "notReal")
    60  
    61  	assert.Assert(t, err != nil)
    62  	assert.Assert(t, errdefs.IsNotFound(err))
    63  }
    64  
    65  func TestGetVolumeByNameNotFound(t *testing.T) {
    66  	v := &volumeRouter{
    67  		backend: &fakeVolumeBackend{},
    68  		cluster: &fakeClusterBackend{swarm: true, manager: true},
    69  	}
    70  
    71  	_, err := callGetVolume(v, "notReal")
    72  
    73  	assert.Assert(t, err != nil)
    74  	assert.Assert(t, errdefs.IsNotFound(err))
    75  }
    76  
    77  func TestGetVolumeByNameFoundRegular(t *testing.T) {
    78  	v := &volumeRouter{
    79  		backend: &fakeVolumeBackend{
    80  			volumes: map[string]*volume.Volume{
    81  
    82  				"volume1": {
    83  					Name: "volume1",
    84  				},
    85  			},
    86  		},
    87  		cluster: &fakeClusterBackend{swarm: true, manager: true},
    88  	}
    89  
    90  	_, err := callGetVolume(v, "volume1")
    91  	assert.NilError(t, err)
    92  }
    93  
    94  func TestGetVolumeByNameFoundSwarm(t *testing.T) {
    95  	v := &volumeRouter{
    96  		backend: &fakeVolumeBackend{},
    97  		cluster: &fakeClusterBackend{
    98  			swarm:   true,
    99  			manager: true,
   100  			volumes: map[string]*volume.Volume{
   101  				"volume1": {
   102  					Name: "volume1",
   103  				},
   104  			},
   105  		},
   106  	}
   107  
   108  	_, err := callGetVolume(v, "volume1")
   109  	assert.NilError(t, err)
   110  }
   111  func TestListVolumes(t *testing.T) {
   112  	v := &volumeRouter{
   113  		backend: &fakeVolumeBackend{
   114  			volumes: map[string]*volume.Volume{
   115  				"v1": {Name: "v1"},
   116  				"v2": {Name: "v2"},
   117  			},
   118  		},
   119  		cluster: &fakeClusterBackend{
   120  			swarm:   true,
   121  			manager: true,
   122  			volumes: map[string]*volume.Volume{
   123  				"v3": {Name: "v3"},
   124  				"v4": {Name: "v4"},
   125  			},
   126  		},
   127  	}
   128  
   129  	resp, err := callListVolumes(v)
   130  	assert.NilError(t, err)
   131  	d := json.NewDecoder(resp.Result().Body)
   132  	respVols := volume.ListResponse{}
   133  	assert.NilError(t, d.Decode(&respVols))
   134  
   135  	assert.Assert(t, respVols.Volumes != nil)
   136  	assert.Equal(t, len(respVols.Volumes), 4, "volumes %v", respVols.Volumes)
   137  }
   138  
   139  func TestListVolumesNoSwarm(t *testing.T) {
   140  	v := &volumeRouter{
   141  		backend: &fakeVolumeBackend{
   142  			volumes: map[string]*volume.Volume{
   143  				"v1": {Name: "v1"},
   144  				"v2": {Name: "v2"},
   145  			},
   146  		},
   147  		cluster: &fakeClusterBackend{},
   148  	}
   149  
   150  	_, err := callListVolumes(v)
   151  	assert.NilError(t, err)
   152  }
   153  
   154  func TestListVolumesNoManager(t *testing.T) {
   155  	v := &volumeRouter{
   156  		backend: &fakeVolumeBackend{
   157  			volumes: map[string]*volume.Volume{
   158  				"v1": {Name: "v1"},
   159  				"v2": {Name: "v2"},
   160  			},
   161  		},
   162  		cluster: &fakeClusterBackend{swarm: true},
   163  	}
   164  
   165  	resp, err := callListVolumes(v)
   166  	assert.NilError(t, err)
   167  
   168  	d := json.NewDecoder(resp.Result().Body)
   169  	respVols := volume.ListResponse{}
   170  	assert.NilError(t, d.Decode(&respVols))
   171  
   172  	assert.Equal(t, len(respVols.Volumes), 2)
   173  	assert.Equal(t, len(respVols.Warnings), 0)
   174  }
   175  
   176  func TestCreateRegularVolume(t *testing.T) {
   177  	b := &fakeVolumeBackend{}
   178  	c := &fakeClusterBackend{
   179  		swarm:   true,
   180  		manager: true,
   181  	}
   182  	v := &volumeRouter{
   183  		backend: b,
   184  		cluster: c,
   185  	}
   186  
   187  	volumeCreate := volume.CreateOptions{
   188  		Name:   "vol1",
   189  		Driver: "foodriver",
   190  	}
   191  
   192  	buf := bytes.Buffer{}
   193  	e := json.NewEncoder(&buf)
   194  	e.Encode(volumeCreate)
   195  
   196  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   197  	req := httptest.NewRequest("POST", "/volumes/create", &buf)
   198  	req.Header.Add("Content-Type", "application/json")
   199  
   200  	resp := httptest.NewRecorder()
   201  	err := v.postVolumesCreate(ctx, resp, req, nil)
   202  
   203  	assert.NilError(t, err)
   204  
   205  	respVolume := volume.Volume{}
   206  
   207  	assert.NilError(t, json.NewDecoder(resp.Result().Body).Decode(&respVolume))
   208  
   209  	assert.Equal(t, respVolume.Name, "vol1")
   210  	assert.Equal(t, respVolume.Driver, "foodriver")
   211  
   212  	assert.Equal(t, 1, len(b.volumes))
   213  	assert.Equal(t, 0, len(c.volumes))
   214  }
   215  
   216  func TestCreateSwarmVolumeNoSwarm(t *testing.T) {
   217  	b := &fakeVolumeBackend{}
   218  	c := &fakeClusterBackend{}
   219  
   220  	v := &volumeRouter{
   221  		backend: b,
   222  		cluster: c,
   223  	}
   224  
   225  	volumeCreate := volume.CreateOptions{
   226  		ClusterVolumeSpec: &volume.ClusterVolumeSpec{},
   227  		Name:              "volCluster",
   228  		Driver:            "someCSI",
   229  	}
   230  
   231  	buf := bytes.Buffer{}
   232  	json.NewEncoder(&buf).Encode(volumeCreate)
   233  
   234  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   235  	req := httptest.NewRequest("POST", "/volumes/create", &buf)
   236  	req.Header.Add("Content-Type", "application/json")
   237  
   238  	resp := httptest.NewRecorder()
   239  	err := v.postVolumesCreate(ctx, resp, req, nil)
   240  
   241  	assert.Assert(t, err != nil)
   242  	assert.Assert(t, errdefs.IsUnavailable(err))
   243  }
   244  
   245  func TestCreateSwarmVolumeNotManager(t *testing.T) {
   246  	b := &fakeVolumeBackend{}
   247  	c := &fakeClusterBackend{swarm: true}
   248  
   249  	v := &volumeRouter{
   250  		backend: b,
   251  		cluster: c,
   252  	}
   253  
   254  	volumeCreate := volume.CreateOptions{
   255  		ClusterVolumeSpec: &volume.ClusterVolumeSpec{},
   256  		Name:              "volCluster",
   257  		Driver:            "someCSI",
   258  	}
   259  
   260  	buf := bytes.Buffer{}
   261  	json.NewEncoder(&buf).Encode(volumeCreate)
   262  
   263  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   264  	req := httptest.NewRequest("POST", "/volumes/create", &buf)
   265  	req.Header.Add("Content-Type", "application/json")
   266  
   267  	resp := httptest.NewRecorder()
   268  	err := v.postVolumesCreate(ctx, resp, req, nil)
   269  
   270  	assert.Assert(t, err != nil)
   271  	assert.Assert(t, errdefs.IsUnavailable(err))
   272  }
   273  
   274  func TestCreateVolumeCluster(t *testing.T) {
   275  	b := &fakeVolumeBackend{}
   276  	c := &fakeClusterBackend{
   277  		swarm:   true,
   278  		manager: true,
   279  	}
   280  
   281  	v := &volumeRouter{
   282  		backend: b,
   283  		cluster: c,
   284  	}
   285  
   286  	volumeCreate := volume.CreateOptions{
   287  		ClusterVolumeSpec: &volume.ClusterVolumeSpec{},
   288  		Name:              "volCluster",
   289  		Driver:            "someCSI",
   290  	}
   291  
   292  	buf := bytes.Buffer{}
   293  	json.NewEncoder(&buf).Encode(volumeCreate)
   294  
   295  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   296  	req := httptest.NewRequest("POST", "/volumes/create", &buf)
   297  	req.Header.Add("Content-Type", "application/json")
   298  
   299  	resp := httptest.NewRecorder()
   300  	err := v.postVolumesCreate(ctx, resp, req, nil)
   301  
   302  	assert.NilError(t, err)
   303  
   304  	respVolume := volume.Volume{}
   305  
   306  	assert.NilError(t, json.NewDecoder(resp.Result().Body).Decode(&respVolume))
   307  
   308  	assert.Equal(t, respVolume.Name, "volCluster")
   309  	assert.Equal(t, respVolume.Driver, "someCSI")
   310  
   311  	assert.Equal(t, 0, len(b.volumes))
   312  	assert.Equal(t, 1, len(c.volumes))
   313  }
   314  
   315  func TestUpdateVolume(t *testing.T) {
   316  	b := &fakeVolumeBackend{}
   317  	c := &fakeClusterBackend{
   318  		swarm:   true,
   319  		manager: true,
   320  		volumes: map[string]*volume.Volume{
   321  			"vol1": {
   322  				Name: "vo1",
   323  				ClusterVolume: &volume.ClusterVolume{
   324  					ID: "vol1",
   325  				},
   326  			},
   327  		},
   328  	}
   329  
   330  	v := &volumeRouter{
   331  		backend: b,
   332  		cluster: c,
   333  	}
   334  
   335  	volumeUpdate := volume.UpdateOptions{
   336  		Spec: &volume.ClusterVolumeSpec{},
   337  	}
   338  
   339  	buf := bytes.Buffer{}
   340  	json.NewEncoder(&buf).Encode(volumeUpdate)
   341  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   342  	req := httptest.NewRequest("POST", "/volumes/vol1/update?version=0", &buf)
   343  	req.Header.Add("Content-Type", "application/json")
   344  
   345  	resp := httptest.NewRecorder()
   346  
   347  	err := v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
   348  	assert.NilError(t, err)
   349  
   350  	assert.Equal(t, c.volumes["vol1"].ClusterVolume.Meta.Version.Index, uint64(1))
   351  }
   352  
   353  func TestUpdateVolumeNoSwarm(t *testing.T) {
   354  	b := &fakeVolumeBackend{}
   355  	c := &fakeClusterBackend{}
   356  
   357  	v := &volumeRouter{
   358  		backend: b,
   359  		cluster: c,
   360  	}
   361  
   362  	volumeUpdate := volume.UpdateOptions{
   363  		Spec: &volume.ClusterVolumeSpec{},
   364  	}
   365  
   366  	buf := bytes.Buffer{}
   367  	json.NewEncoder(&buf).Encode(volumeUpdate)
   368  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   369  	req := httptest.NewRequest("POST", "/volumes/vol1/update?version=0", &buf)
   370  	req.Header.Add("Content-Type", "application/json")
   371  
   372  	resp := httptest.NewRecorder()
   373  
   374  	err := v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
   375  	assert.Assert(t, err != nil)
   376  	assert.Assert(t, errdefs.IsUnavailable(err))
   377  }
   378  
   379  func TestUpdateVolumeNotFound(t *testing.T) {
   380  	b := &fakeVolumeBackend{}
   381  	c := &fakeClusterBackend{
   382  		swarm:   true,
   383  		manager: true,
   384  		volumes: map[string]*volume.Volume{},
   385  	}
   386  
   387  	v := &volumeRouter{
   388  		backend: b,
   389  		cluster: c,
   390  	}
   391  
   392  	volumeUpdate := volume.UpdateOptions{
   393  		Spec: &volume.ClusterVolumeSpec{},
   394  	}
   395  
   396  	buf := bytes.Buffer{}
   397  	json.NewEncoder(&buf).Encode(volumeUpdate)
   398  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   399  	req := httptest.NewRequest("POST", "/volumes/vol1/update?version=0", &buf)
   400  	req.Header.Add("Content-Type", "application/json")
   401  
   402  	resp := httptest.NewRecorder()
   403  
   404  	err := v.putVolumesUpdate(ctx, resp, req, map[string]string{"name": "vol1"})
   405  	assert.Assert(t, err != nil)
   406  	assert.Assert(t, errdefs.IsNotFound(err))
   407  }
   408  
   409  func TestVolumeRemove(t *testing.T) {
   410  	b := &fakeVolumeBackend{
   411  		volumes: map[string]*volume.Volume{
   412  			"vol1": {
   413  				Name: "vol1",
   414  			},
   415  		},
   416  	}
   417  	c := &fakeClusterBackend{swarm: true, manager: true}
   418  
   419  	v := &volumeRouter{
   420  		backend: b,
   421  		cluster: c,
   422  	}
   423  
   424  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   425  	req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
   426  	resp := httptest.NewRecorder()
   427  
   428  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   429  	assert.NilError(t, err)
   430  	assert.Equal(t, len(b.volumes), 0)
   431  }
   432  
   433  func TestVolumeRemoveSwarm(t *testing.T) {
   434  	b := &fakeVolumeBackend{}
   435  	c := &fakeClusterBackend{
   436  		swarm:   true,
   437  		manager: true,
   438  		volumes: map[string]*volume.Volume{
   439  			"vol1": {
   440  				Name:          "vol1",
   441  				ClusterVolume: &volume.ClusterVolume{},
   442  			},
   443  		},
   444  	}
   445  
   446  	v := &volumeRouter{
   447  		backend: b,
   448  		cluster: c,
   449  	}
   450  
   451  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   452  	req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
   453  	resp := httptest.NewRecorder()
   454  
   455  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   456  	assert.NilError(t, err)
   457  	assert.Equal(t, len(c.volumes), 0)
   458  }
   459  
   460  func TestVolumeRemoveNotFoundNoSwarm(t *testing.T) {
   461  	b := &fakeVolumeBackend{}
   462  	c := &fakeClusterBackend{}
   463  	v := &volumeRouter{
   464  		backend: b,
   465  		cluster: c,
   466  	}
   467  
   468  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   469  	req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
   470  	resp := httptest.NewRecorder()
   471  
   472  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   473  	assert.Assert(t, err != nil)
   474  	assert.Assert(t, errdefs.IsNotFound(err), err.Error())
   475  }
   476  
   477  func TestVolumeRemoveNotFoundNoManager(t *testing.T) {
   478  	b := &fakeVolumeBackend{}
   479  	c := &fakeClusterBackend{swarm: true}
   480  	v := &volumeRouter{
   481  		backend: b,
   482  		cluster: c,
   483  	}
   484  
   485  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   486  	req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
   487  	resp := httptest.NewRecorder()
   488  
   489  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   490  	assert.Assert(t, err != nil)
   491  	assert.Assert(t, errdefs.IsNotFound(err))
   492  }
   493  
   494  func TestVolumeRemoveFoundNoSwarm(t *testing.T) {
   495  	b := &fakeVolumeBackend{
   496  		volumes: map[string]*volume.Volume{
   497  			"vol1": {
   498  				Name: "vol1",
   499  			},
   500  		},
   501  	}
   502  	c := &fakeClusterBackend{}
   503  
   504  	v := &volumeRouter{
   505  		backend: b,
   506  		cluster: c,
   507  	}
   508  
   509  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   510  	req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
   511  	resp := httptest.NewRecorder()
   512  
   513  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   514  	assert.NilError(t, err)
   515  	assert.Equal(t, len(b.volumes), 0)
   516  }
   517  
   518  func TestVolumeRemoveNoSwarmInUse(t *testing.T) {
   519  	b := &fakeVolumeBackend{
   520  		volumes: map[string]*volume.Volume{
   521  			"inuse": {
   522  				Name: "inuse",
   523  			},
   524  		},
   525  	}
   526  	c := &fakeClusterBackend{}
   527  	v := &volumeRouter{
   528  		backend: b,
   529  		cluster: c,
   530  	}
   531  
   532  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   533  	req := httptest.NewRequest("DELETE", "/volumes/inuse", nil)
   534  	resp := httptest.NewRecorder()
   535  
   536  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "inuse"})
   537  	assert.Assert(t, err != nil)
   538  	assert.Assert(t, errdefs.IsConflict(err))
   539  }
   540  
   541  func TestVolumeRemoveSwarmForce(t *testing.T) {
   542  	b := &fakeVolumeBackend{}
   543  	c := &fakeClusterBackend{
   544  		swarm:   true,
   545  		manager: true,
   546  		volumes: map[string]*volume.Volume{
   547  			"vol1": {
   548  				Name:          "vol1",
   549  				ClusterVolume: &volume.ClusterVolume{},
   550  				Options:       map[string]string{"mustforce": "yes"},
   551  			},
   552  		},
   553  	}
   554  
   555  	v := &volumeRouter{
   556  		backend: b,
   557  		cluster: c,
   558  	}
   559  
   560  	ctx := context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   561  	req := httptest.NewRequest("DELETE", "/volumes/vol1", nil)
   562  	resp := httptest.NewRecorder()
   563  
   564  	err := v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   565  
   566  	assert.Assert(t, err != nil)
   567  	assert.Assert(t, errdefs.IsConflict(err))
   568  
   569  	ctx = context.WithValue(context.Background(), httputils.APIVersionKey{}, clusterVolumesVersion)
   570  	req = httptest.NewRequest("DELETE", "/volumes/vol1?force=1", nil)
   571  	resp = httptest.NewRecorder()
   572  
   573  	err = v.deleteVolumes(ctx, resp, req, map[string]string{"name": "vol1"})
   574  
   575  	assert.NilError(t, err)
   576  	assert.Equal(t, len(b.volumes), 0)
   577  	assert.Equal(t, len(c.volumes), 0)
   578  }
   579  
   580  type fakeVolumeBackend struct {
   581  	volumes map[string]*volume.Volume
   582  }
   583  
   584  func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]*volume.Volume, []string, error) {
   585  	volumes := []*volume.Volume{}
   586  	for _, v := range b.volumes {
   587  		volumes = append(volumes, v)
   588  	}
   589  	return volumes, nil, nil
   590  }
   591  
   592  func (b *fakeVolumeBackend) Get(_ context.Context, name string, _ ...opts.GetOption) (*volume.Volume, error) {
   593  	if v, ok := b.volumes[name]; ok {
   594  		return v, nil
   595  	}
   596  	return nil, errdefs.NotFound(fmt.Errorf("volume %s not found", name))
   597  }
   598  
   599  func (b *fakeVolumeBackend) Create(_ context.Context, name, driverName string, _ ...opts.CreateOption) (*volume.Volume, error) {
   600  	if _, ok := b.volumes[name]; ok {
   601  		// TODO(dperny): return appropriate error type
   602  		return nil, fmt.Errorf("already exists")
   603  	}
   604  
   605  	v := &volume.Volume{
   606  		Name:   name,
   607  		Driver: driverName,
   608  	}
   609  	if b.volumes == nil {
   610  		b.volumes = map[string]*volume.Volume{
   611  			name: v,
   612  		}
   613  	} else {
   614  		b.volumes[name] = v
   615  	}
   616  
   617  	return v, nil
   618  }
   619  
   620  func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.RemoveOption) error {
   621  	removeOpts := &opts.RemoveConfig{}
   622  	for _, opt := range o {
   623  		opt(removeOpts)
   624  	}
   625  
   626  	if v, ok := b.volumes[name]; !ok {
   627  		if !removeOpts.PurgeOnError {
   628  			return errdefs.NotFound(fmt.Errorf("volume %s not found", name))
   629  		}
   630  	} else if v.Name == "inuse" {
   631  		return errdefs.Conflict(fmt.Errorf("volume in use"))
   632  	}
   633  
   634  	delete(b.volumes, name)
   635  
   636  	return nil
   637  }
   638  
   639  func (b *fakeVolumeBackend) Prune(_ context.Context, _ filters.Args) (*types.VolumesPruneReport, error) {
   640  	return nil, nil
   641  }
   642  
   643  type fakeClusterBackend struct {
   644  	swarm   bool
   645  	manager bool
   646  	idCount int
   647  	volumes map[string]*volume.Volume
   648  }
   649  
   650  func (c *fakeClusterBackend) checkSwarm() error {
   651  	if !c.swarm {
   652  		return errdefs.Unavailable(fmt.Errorf("this node is not a swarm manager. Use \"docker swarm init\" or \"docker swarm join\" to connect this node to swarm and try again"))
   653  	} else if !c.manager {
   654  		return errdefs.Unavailable(fmt.Errorf("this node is not a swarm manager. Worker nodes can't be used to view or modify cluster state. Please run this command on a manager node or promote the current node to a manager"))
   655  	}
   656  
   657  	return nil
   658  }
   659  
   660  func (c *fakeClusterBackend) IsManager() bool {
   661  	return c.swarm && c.manager
   662  }
   663  
   664  func (c *fakeClusterBackend) GetVolume(nameOrID string) (volume.Volume, error) {
   665  	if err := c.checkSwarm(); err != nil {
   666  		return volume.Volume{}, err
   667  	}
   668  
   669  	if v, ok := c.volumes[nameOrID]; ok {
   670  		return *v, nil
   671  	}
   672  	return volume.Volume{}, errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
   673  }
   674  
   675  func (c *fakeClusterBackend) GetVolumes(options volume.ListOptions) ([]*volume.Volume, error) {
   676  	if err := c.checkSwarm(); err != nil {
   677  		return nil, err
   678  	}
   679  
   680  	volumes := []*volume.Volume{}
   681  
   682  	for _, v := range c.volumes {
   683  		volumes = append(volumes, v)
   684  	}
   685  	return volumes, nil
   686  }
   687  
   688  func (c *fakeClusterBackend) CreateVolume(volumeCreate volume.CreateOptions) (*volume.Volume, error) {
   689  	if err := c.checkSwarm(); err != nil {
   690  		return nil, err
   691  	}
   692  
   693  	if _, ok := c.volumes[volumeCreate.Name]; ok {
   694  		// TODO(dperny): return appropriate already exists error
   695  		return nil, fmt.Errorf("already exists")
   696  	}
   697  
   698  	v := &volume.Volume{
   699  		Name:    volumeCreate.Name,
   700  		Driver:  volumeCreate.Driver,
   701  		Labels:  volumeCreate.Labels,
   702  		Options: volumeCreate.DriverOpts,
   703  		Scope:   "global",
   704  	}
   705  
   706  	v.ClusterVolume = &volume.ClusterVolume{
   707  		ID:   fmt.Sprintf("cluster_%d", c.idCount),
   708  		Spec: *volumeCreate.ClusterVolumeSpec,
   709  	}
   710  
   711  	c.idCount = c.idCount + 1
   712  	if c.volumes == nil {
   713  		c.volumes = map[string]*volume.Volume{
   714  			v.Name: v,
   715  		}
   716  	} else {
   717  		c.volumes[v.Name] = v
   718  	}
   719  
   720  	return v, nil
   721  }
   722  
   723  func (c *fakeClusterBackend) RemoveVolume(nameOrID string, force bool) error {
   724  	if err := c.checkSwarm(); err != nil {
   725  		return err
   726  	}
   727  
   728  	v, ok := c.volumes[nameOrID]
   729  	if !ok {
   730  		return errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
   731  	}
   732  
   733  	if _, mustforce := v.Options["mustforce"]; mustforce && !force {
   734  		return errdefs.Conflict(fmt.Errorf("volume %s must be force removed", nameOrID))
   735  	}
   736  
   737  	delete(c.volumes, nameOrID)
   738  
   739  	return nil
   740  }
   741  
   742  func (c *fakeClusterBackend) UpdateVolume(nameOrID string, version uint64, _ volume.UpdateOptions) error {
   743  	if err := c.checkSwarm(); err != nil {
   744  		return err
   745  	}
   746  
   747  	if v, ok := c.volumes[nameOrID]; ok {
   748  		if v.ClusterVolume.Meta.Version.Index != version {
   749  			return fmt.Errorf("wrong version")
   750  		}
   751  		v.ClusterVolume.Meta.Version.Index = v.ClusterVolume.Meta.Version.Index + 1
   752  		// for testing, we don't actually need to change anything about the
   753  		// volume object. let's just increment the version so we can see the
   754  		// call happened.
   755  	} else {
   756  		return errdefs.NotFound(fmt.Errorf("volume %q not found", nameOrID))
   757  	}
   758  
   759  	return nil
   760  }