volume_routes_test.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760
  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. assert.Equal(t, len(c.volumes), 0)
  466. }
  467. type fakeVolumeBackend struct {
  468. volumes map[string]*volume.Volume
  469. }
  470. func (b *fakeVolumeBackend) List(_ context.Context, _ filters.Args) ([]*volume.Volume, []string, error) {
  471. volumes := []*volume.Volume{}
  472. for _, v := range b.volumes {
  473. volumes = append(volumes, v)
  474. }
  475. return volumes, nil, nil
  476. }
  477. func (b *fakeVolumeBackend) Get(_ context.Context, name string, _ ...opts.GetOption) (*volume.Volume, error) {
  478. if v, ok := b.volumes[name]; ok {
  479. return v, nil
  480. }
  481. return nil, errdefs.NotFound(fmt.Errorf("volume %s not found", name))
  482. }
  483. func (b *fakeVolumeBackend) Create(_ context.Context, name, driverName string, _ ...opts.CreateOption) (*volume.Volume, error) {
  484. if _, ok := b.volumes[name]; ok {
  485. // TODO(dperny): return appropriate error type
  486. return nil, fmt.Errorf("already exists")
  487. }
  488. v := &volume.Volume{
  489. Name: name,
  490. Driver: driverName,
  491. }
  492. if b.volumes == nil {
  493. b.volumes = map[string]*volume.Volume{
  494. name: v,
  495. }
  496. } else {
  497. b.volumes[name] = v
  498. }
  499. return v, nil
  500. }
  501. func (b *fakeVolumeBackend) Remove(_ context.Context, name string, o ...opts.RemoveOption) error {
  502. removeOpts := &opts.RemoveConfig{}
  503. for _, opt := range o {
  504. opt(removeOpts)
  505. }
  506. if v, ok := b.volumes[name]; !ok {
  507. if !removeOpts.PurgeOnError {
  508. return errdefs.NotFound(fmt.Errorf("volume %s not found", name))
  509. }
  510. } else if v.Name == "inuse" {
  511. return errdefs.Conflict(fmt.Errorf("volume in use"))
  512. }
  513. delete(b.volumes, name)
  514. return nil
  515. }
  516. func (b *fakeVolumeBackend) Prune(_ context.Context, _ filters.Args) (*types.VolumesPruneReport, error) {
  517. return nil, nil
  518. }
  519. type fakeClusterBackend struct {
  520. swarm bool
  521. manager bool
  522. idCount int
  523. volumes map[string]*volume.Volume
  524. }
  525. func (c *fakeClusterBackend) checkSwarm() error {
  526. if !c.swarm {
  527. 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"))
  528. } else if !c.manager {
  529. 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"))
  530. }
  531. return nil
  532. }
  533. func (c *fakeClusterBackend) IsManager() bool {
  534. return c.swarm && c.manager
  535. }
  536. func (c *fakeClusterBackend) GetVolume(nameOrID string) (volume.Volume, error) {
  537. if err := c.checkSwarm(); err != nil {
  538. return volume.Volume{}, err
  539. }
  540. if v, ok := c.volumes[nameOrID]; ok {
  541. return *v, nil
  542. }
  543. return volume.Volume{}, errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
  544. }
  545. func (c *fakeClusterBackend) GetVolumes(options volume.ListOptions) ([]*volume.Volume, error) {
  546. if err := c.checkSwarm(); err != nil {
  547. return nil, err
  548. }
  549. volumes := []*volume.Volume{}
  550. for _, v := range c.volumes {
  551. volumes = append(volumes, v)
  552. }
  553. return volumes, nil
  554. }
  555. func (c *fakeClusterBackend) CreateVolume(volumeCreate volume.CreateOptions) (*volume.Volume, error) {
  556. if err := c.checkSwarm(); err != nil {
  557. return nil, err
  558. }
  559. if _, ok := c.volumes[volumeCreate.Name]; ok {
  560. // TODO(dperny): return appropriate already exists error
  561. return nil, fmt.Errorf("already exists")
  562. }
  563. v := &volume.Volume{
  564. Name: volumeCreate.Name,
  565. Driver: volumeCreate.Driver,
  566. Labels: volumeCreate.Labels,
  567. Options: volumeCreate.DriverOpts,
  568. Scope: "global",
  569. }
  570. v.ClusterVolume = &volume.ClusterVolume{
  571. ID: fmt.Sprintf("cluster_%d", c.idCount),
  572. Spec: *volumeCreate.ClusterVolumeSpec,
  573. }
  574. c.idCount = c.idCount + 1
  575. if c.volumes == nil {
  576. c.volumes = map[string]*volume.Volume{
  577. v.Name: v,
  578. }
  579. } else {
  580. c.volumes[v.Name] = v
  581. }
  582. return v, nil
  583. }
  584. func (c *fakeClusterBackend) RemoveVolume(nameOrID string, force bool) error {
  585. if err := c.checkSwarm(); err != nil {
  586. return err
  587. }
  588. v, ok := c.volumes[nameOrID]
  589. if !ok {
  590. return errdefs.NotFound(fmt.Errorf("volume %s not found", nameOrID))
  591. }
  592. if _, mustforce := v.Options["mustforce"]; mustforce && !force {
  593. return errdefs.Conflict(fmt.Errorf("volume %s must be force removed", nameOrID))
  594. }
  595. delete(c.volumes, nameOrID)
  596. return nil
  597. }
  598. func (c *fakeClusterBackend) UpdateVolume(nameOrID string, version uint64, _ volume.UpdateOptions) error {
  599. if err := c.checkSwarm(); err != nil {
  600. return err
  601. }
  602. if v, ok := c.volumes[nameOrID]; ok {
  603. if v.ClusterVolume.Meta.Version.Index != version {
  604. return fmt.Errorf("wrong version")
  605. }
  606. v.ClusterVolume.Meta.Version.Index = v.ClusterVolume.Meta.Version.Index + 1
  607. // for testing, we don't actually need to change anything about the
  608. // volume object. let's just increment the version so we can see the
  609. // call happened.
  610. } else {
  611. return errdefs.NotFound(fmt.Errorf("volume %q not found", nameOrID))
  612. }
  613. return nil
  614. }