Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -34,7 +34,6 @@ func TestVolumesCreateAndList(t *testing.T) {
|
| 34 | 34 |
Driver: "local", |
| 35 | 35 |
Scope: "local", |
| 36 | 36 |
Name: name, |
| 37 |
- Options: map[string]string{},
|
|
| 38 | 37 |
Mountpoint: fmt.Sprintf("%s/volumes/%s/_data", testEnv.DaemonInfo.DockerRootDir, name),
|
| 39 | 38 |
} |
| 40 | 39 |
assert.Equal(t, vol, expected) |
| ... | ... |
@@ -95,7 +94,6 @@ func TestVolumesInspect(t *testing.T) {
|
| 95 | 95 |
Driver: "local", |
| 96 | 96 |
Scope: "local", |
| 97 | 97 |
Name: name, |
| 98 |
- Options: map[string]string{},
|
|
| 99 | 98 |
Mountpoint: fmt.Sprintf("%s/volumes/%s/_data", testEnv.DaemonInfo.DockerRootDir, name),
|
| 100 | 99 |
} |
| 101 | 100 |
assert.Equal(t, vol, expected) |
| ... | ... |
@@ -4,6 +4,7 @@ import ( |
| 4 | 4 |
"encoding/json" |
| 5 | 5 |
|
| 6 | 6 |
"github.com/boltdb/bolt" |
| 7 |
+ "github.com/docker/docker/errdefs" |
|
| 7 | 8 |
"github.com/pkg/errors" |
| 8 | 9 |
"github.com/sirupsen/logrus" |
| 9 | 10 |
) |
| ... | ... |
@@ -28,7 +29,10 @@ func setMeta(tx *bolt.Tx, name string, meta volumeMetadata) error {
|
| 28 | 28 |
if err != nil {
|
| 29 | 29 |
return err |
| 30 | 30 |
} |
| 31 |
- b := tx.Bucket(volumeBucketName) |
|
| 31 |
+ b, err := tx.CreateBucketIfNotExists(volumeBucketName) |
|
| 32 |
+ if err != nil {
|
|
| 33 |
+ return errors.Wrap(err, "error creating volume bucket") |
|
| 34 |
+ } |
|
| 32 | 35 |
return errors.Wrap(b.Put([]byte(name), metaJSON), "error setting volume metadata") |
| 33 | 36 |
} |
| 34 | 37 |
|
| ... | ... |
@@ -42,8 +46,11 @@ func (s *VolumeStore) getMeta(name string) (volumeMetadata, error) {
|
| 42 | 42 |
|
| 43 | 43 |
func getMeta(tx *bolt.Tx, name string, meta *volumeMetadata) error {
|
| 44 | 44 |
b := tx.Bucket(volumeBucketName) |
| 45 |
+ if b == nil {
|
|
| 46 |
+ return errdefs.NotFound(errors.New("volume bucket does not exist"))
|
|
| 47 |
+ } |
|
| 45 | 48 |
val := b.Get([]byte(name)) |
| 46 |
- if string(val) == "" {
|
|
| 49 |
+ if len(val) == 0 {
|
|
| 47 | 50 |
return nil |
| 48 | 51 |
} |
| 49 | 52 |
if err := json.Unmarshal(val, meta); err != nil {
|
| 50 | 53 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,51 @@ |
| 0 |
+package store |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "io/ioutil" |
|
| 4 |
+ "os" |
|
| 5 |
+ "path/filepath" |
|
| 6 |
+ "testing" |
|
| 7 |
+ "time" |
|
| 8 |
+ |
|
| 9 |
+ "github.com/boltdb/bolt" |
|
| 10 |
+ "github.com/stretchr/testify/require" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+func TestSetGetMeta(t *testing.T) {
|
|
| 14 |
+ t.Parallel() |
|
| 15 |
+ |
|
| 16 |
+ dir, err := ioutil.TempDir("", "test-set-get")
|
|
| 17 |
+ require.NoError(t, err) |
|
| 18 |
+ defer os.RemoveAll(dir) |
|
| 19 |
+ |
|
| 20 |
+ db, err := bolt.Open(filepath.Join(dir, "db"), 0600, &bolt.Options{Timeout: 1 * time.Second})
|
|
| 21 |
+ require.NoError(t, err) |
|
| 22 |
+ |
|
| 23 |
+ store := &VolumeStore{db: db}
|
|
| 24 |
+ |
|
| 25 |
+ _, err = store.getMeta("test")
|
|
| 26 |
+ require.Error(t, err) |
|
| 27 |
+ |
|
| 28 |
+ err = db.Update(func(tx *bolt.Tx) error {
|
|
| 29 |
+ _, err := tx.CreateBucket(volumeBucketName) |
|
| 30 |
+ return err |
|
| 31 |
+ }) |
|
| 32 |
+ require.NoError(t, err) |
|
| 33 |
+ |
|
| 34 |
+ meta, err := store.getMeta("test")
|
|
| 35 |
+ require.NoError(t, err) |
|
| 36 |
+ require.Equal(t, volumeMetadata{}, meta)
|
|
| 37 |
+ |
|
| 38 |
+ testMeta := volumeMetadata{
|
|
| 39 |
+ Name: "test", |
|
| 40 |
+ Driver: "fake", |
|
| 41 |
+ Labels: map[string]string{"a": "1", "b": "2"},
|
|
| 42 |
+ Options: map[string]string{"foo": "bar"},
|
|
| 43 |
+ } |
|
| 44 |
+ err = store.setMeta("test", testMeta)
|
|
| 45 |
+ require.NoError(t, err) |
|
| 46 |
+ |
|
| 47 |
+ meta, err = store.getMeta("test")
|
|
| 48 |
+ require.NoError(t, err) |
|
| 49 |
+ require.Equal(t, testMeta, meta) |
|
| 50 |
+} |
| 0 | 51 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,55 @@ |
| 0 |
+package store |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "io/ioutil" |
|
| 4 |
+ "os" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/volume" |
|
| 8 |
+ volumedrivers "github.com/docker/docker/volume/drivers" |
|
| 9 |
+ volumetestutils "github.com/docker/docker/volume/testutils" |
|
| 10 |
+ "github.com/stretchr/testify/require" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+func TestRestore(t *testing.T) {
|
|
| 14 |
+ t.Parallel() |
|
| 15 |
+ |
|
| 16 |
+ dir, err := ioutil.TempDir("", "test-restore")
|
|
| 17 |
+ require.NoError(t, err) |
|
| 18 |
+ defer os.RemoveAll(dir) |
|
| 19 |
+ |
|
| 20 |
+ driverName := "test-restore" |
|
| 21 |
+ volumedrivers.Register(volumetestutils.NewFakeDriver(driverName), driverName) |
|
| 22 |
+ defer volumedrivers.Unregister("test-restore")
|
|
| 23 |
+ |
|
| 24 |
+ s, err := New(dir) |
|
| 25 |
+ require.NoError(t, err) |
|
| 26 |
+ defer s.Shutdown() |
|
| 27 |
+ |
|
| 28 |
+ _, err = s.Create("test1", driverName, nil, nil)
|
|
| 29 |
+ require.NoError(t, err) |
|
| 30 |
+ |
|
| 31 |
+ testLabels := map[string]string{"a": "1"}
|
|
| 32 |
+ testOpts := map[string]string{"foo": "bar"}
|
|
| 33 |
+ _, err = s.Create("test2", driverName, testOpts, testLabels)
|
|
| 34 |
+ require.NoError(t, err) |
|
| 35 |
+ |
|
| 36 |
+ s.Shutdown() |
|
| 37 |
+ |
|
| 38 |
+ s, err = New(dir) |
|
| 39 |
+ require.NoError(t, err) |
|
| 40 |
+ |
|
| 41 |
+ v, err := s.Get("test1")
|
|
| 42 |
+ require.NoError(t, err) |
|
| 43 |
+ |
|
| 44 |
+ dv := v.(volume.DetailedVolume) |
|
| 45 |
+ var nilMap map[string]string |
|
| 46 |
+ require.Equal(t, nilMap, dv.Options()) |
|
| 47 |
+ require.Equal(t, nilMap, dv.Labels()) |
|
| 48 |
+ |
|
| 49 |
+ v, err = s.Get("test2")
|
|
| 50 |
+ require.NoError(t, err) |
|
| 51 |
+ dv = v.(volume.DetailedVolume) |
|
| 52 |
+ require.Equal(t, testOpts, dv.Options()) |
|
| 53 |
+ require.Equal(t, testLabels, dv.Labels()) |
|
| 54 |
+} |
| ... | ... |
@@ -29,7 +29,10 @@ type volumeWrapper struct {
|
| 29 | 29 |
} |
| 30 | 30 |
|
| 31 | 31 |
func (v volumeWrapper) Options() map[string]string {
|
| 32 |
- options := map[string]string{}
|
|
| 32 |
+ if v.options == nil {
|
|
| 33 |
+ return nil |
|
| 34 |
+ } |
|
| 35 |
+ options := make(map[string]string, len(v.options)) |
|
| 33 | 36 |
for key, value := range v.options {
|
| 34 | 37 |
options[key] = value |
| 35 | 38 |
} |
| ... | ... |
@@ -37,7 +40,15 @@ func (v volumeWrapper) Options() map[string]string {
|
| 37 | 37 |
} |
| 38 | 38 |
|
| 39 | 39 |
func (v volumeWrapper) Labels() map[string]string {
|
| 40 |
- return v.labels |
|
| 40 |
+ if v.labels == nil {
|
|
| 41 |
+ return nil |
|
| 42 |
+ } |
|
| 43 |
+ |
|
| 44 |
+ labels := make(map[string]string, len(v.labels)) |
|
| 45 |
+ for key, value := range v.labels {
|
|
| 46 |
+ labels[key] = value |
|
| 47 |
+ } |
|
| 48 |
+ return labels |
|
| 41 | 49 |
} |
| 42 | 50 |
|
| 43 | 51 |
func (v volumeWrapper) Scope() string {
|
| ... | ... |
@@ -12,6 +12,8 @@ import ( |
| 12 | 12 |
"github.com/docker/docker/volume" |
| 13 | 13 |
"github.com/docker/docker/volume/drivers" |
| 14 | 14 |
volumetestutils "github.com/docker/docker/volume/testutils" |
| 15 |
+ "github.com/stretchr/testify/assert" |
|
| 16 |
+ "github.com/stretchr/testify/require" |
|
| 15 | 17 |
) |
| 16 | 18 |
|
| 17 | 19 |
func TestCreate(t *testing.T) {
|
| ... | ... |
@@ -291,6 +293,7 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
|
| 291 | 291 |
|
| 292 | 292 |
pg := volumetestutils.NewFakePluginGetter(p) |
| 293 | 293 |
volumedrivers.RegisterPluginGetter(pg) |
| 294 |
+ defer volumedrivers.RegisterPluginGetter(nil) |
|
| 294 | 295 |
|
| 295 | 296 |
dir, err := ioutil.TempDir("", "test-plugin-deref-err")
|
| 296 | 297 |
if err != nil {
|
| ... | ... |
@@ -320,3 +323,103 @@ func TestDefererencePluginOnCreateError(t *testing.T) {
|
| 320 | 320 |
t.Fatalf("expected 1 plugin reference, got: %d", refs)
|
| 321 | 321 |
} |
| 322 | 322 |
} |
| 323 |
+ |
|
| 324 |
+func TestRefDerefRemove(t *testing.T) {
|
|
| 325 |
+ t.Parallel() |
|
| 326 |
+ |
|
| 327 |
+ driverName := "test-ref-deref-remove" |
|
| 328 |
+ s, cleanup := setupTest(t, driverName) |
|
| 329 |
+ defer cleanup(t) |
|
| 330 |
+ |
|
| 331 |
+ v, err := s.CreateWithRef("test", driverName, "test-ref", nil, nil)
|
|
| 332 |
+ require.NoError(t, err) |
|
| 333 |
+ |
|
| 334 |
+ err = s.Remove(v) |
|
| 335 |
+ require.Error(t, err) |
|
| 336 |
+ require.Equal(t, errVolumeInUse, err.(*OpErr).Err) |
|
| 337 |
+ |
|
| 338 |
+ s.Dereference(v, "test-ref") |
|
| 339 |
+ err = s.Remove(v) |
|
| 340 |
+ require.NoError(t, err) |
|
| 341 |
+} |
|
| 342 |
+ |
|
| 343 |
+func TestGet(t *testing.T) {
|
|
| 344 |
+ t.Parallel() |
|
| 345 |
+ |
|
| 346 |
+ driverName := "test-get" |
|
| 347 |
+ s, cleanup := setupTest(t, driverName) |
|
| 348 |
+ defer cleanup(t) |
|
| 349 |
+ |
|
| 350 |
+ _, err := s.Get("not-exist")
|
|
| 351 |
+ require.Error(t, err) |
|
| 352 |
+ require.Equal(t, errNoSuchVolume, err.(*OpErr).Err) |
|
| 353 |
+ |
|
| 354 |
+ v1, err := s.Create("test", driverName, nil, map[string]string{"a": "1"})
|
|
| 355 |
+ require.NoError(t, err) |
|
| 356 |
+ |
|
| 357 |
+ v2, err := s.Get("test")
|
|
| 358 |
+ require.NoError(t, err) |
|
| 359 |
+ require.Equal(t, v1, v2) |
|
| 360 |
+ |
|
| 361 |
+ dv := v2.(volume.DetailedVolume) |
|
| 362 |
+ require.Equal(t, "1", dv.Labels()["a"]) |
|
| 363 |
+ |
|
| 364 |
+ err = s.Remove(v1) |
|
| 365 |
+ require.NoError(t, err) |
|
| 366 |
+} |
|
| 367 |
+ |
|
| 368 |
+func TestGetWithRef(t *testing.T) {
|
|
| 369 |
+ t.Parallel() |
|
| 370 |
+ |
|
| 371 |
+ driverName := "test-get-with-ref" |
|
| 372 |
+ s, cleanup := setupTest(t, driverName) |
|
| 373 |
+ defer cleanup(t) |
|
| 374 |
+ |
|
| 375 |
+ _, err := s.GetWithRef("not-exist", driverName, "test-ref")
|
|
| 376 |
+ require.Error(t, err) |
|
| 377 |
+ |
|
| 378 |
+ v1, err := s.Create("test", driverName, nil, map[string]string{"a": "1"})
|
|
| 379 |
+ require.NoError(t, err) |
|
| 380 |
+ |
|
| 381 |
+ v2, err := s.GetWithRef("test", driverName, "test-ref")
|
|
| 382 |
+ require.NoError(t, err) |
|
| 383 |
+ require.Equal(t, v1, v2) |
|
| 384 |
+ |
|
| 385 |
+ err = s.Remove(v2) |
|
| 386 |
+ require.Error(t, err) |
|
| 387 |
+ require.Equal(t, errVolumeInUse, err.(*OpErr).Err) |
|
| 388 |
+ |
|
| 389 |
+ s.Dereference(v2, "test-ref") |
|
| 390 |
+ err = s.Remove(v2) |
|
| 391 |
+ require.NoError(t, err) |
|
| 392 |
+} |
|
| 393 |
+ |
|
| 394 |
+func setupTest(t *testing.T, name string) (*VolumeStore, func(*testing.T)) {
|
|
| 395 |
+ t.Helper() |
|
| 396 |
+ s, cleanup := newTestStore(t) |
|
| 397 |
+ |
|
| 398 |
+ volumedrivers.Register(volumetestutils.NewFakeDriver(name), name) |
|
| 399 |
+ return s, func(t *testing.T) {
|
|
| 400 |
+ cleanup(t) |
|
| 401 |
+ volumedrivers.Unregister(name) |
|
| 402 |
+ } |
|
| 403 |
+} |
|
| 404 |
+ |
|
| 405 |
+func newTestStore(t *testing.T) (*VolumeStore, func(*testing.T)) {
|
|
| 406 |
+ t.Helper() |
|
| 407 |
+ |
|
| 408 |
+ dir, err := ioutil.TempDir("", "store-root")
|
|
| 409 |
+ require.NoError(t, err) |
|
| 410 |
+ |
|
| 411 |
+ cleanup := func(t *testing.T) {
|
|
| 412 |
+ err := os.RemoveAll(dir) |
|
| 413 |
+ assert.NoError(t, err) |
|
| 414 |
+ } |
|
| 415 |
+ |
|
| 416 |
+ s, err := New(dir) |
|
| 417 |
+ assert.NoError(t, err) |
|
| 418 |
+ return s, func(t *testing.T) {
|
|
| 419 |
+ s.Shutdown() |
|
| 420 |
+ cleanup(t) |
|
| 421 |
+ } |
|
| 422 |
+} |