volume_routes_test.go 19 KB

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