The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6339

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
This PR comes from #6285, but to make that PR smaller I am breaking it into parts.

This PR adds some generic storage driver utils which will be used by the driver implementations to come.
From 38ba4ac1342b7e5f0f7b54b74de059f4df856a59 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Sun, 6 Oct 2019 22:44:13 -0400
Subject: [PATCH 1/6] lxd/storage/drivers/utils: Add common functions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/utils.go | 141 +++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 lxd/storage/drivers/utils.go

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
new file mode 100644
index 0000000000..e0cf6ce803
--- /dev/null
+++ b/lxd/storage/drivers/utils.go
@@ -0,0 +1,141 @@
+package drivers
+
+import (
+       "io/ioutil"
+       "os"
+       "path/filepath"
+       "time"
+
+       "golang.org/x/sys/unix"
+
+       "github.com/lxc/lxd/shared"
+       "github.com/lxc/lxd/shared/api"
+)
+
+func wipeDirectory(path string) error {
+       // List all entries
+       entries, err := ioutil.ReadDir(path)
+       if err != nil {
+               if os.IsNotExist(err) {
+                       return nil
+               }
+       }
+
+       // Individually wipe all entries
+       for _, entry := range entries {
+               entryPath := filepath.Join(path, entry.Name())
+               err := os.RemoveAll(entryPath)
+               if err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}
+
+func forceUnmount(path string) (bool, error) {
+       unmounted := false
+
+       for {
+               // Check if already unmounted
+               if !shared.IsMountPoint(path) {
+                       return unmounted, nil
+               }
+
+               // Try a clean unmount first
+               err := unix.Unmount(path, 0)
+               if err != nil {
+                       // Fallback to lazy unmounting
+                       err = unix.Unmount(path, unix.MNT_DETACH)
+                       if err != nil {
+                               return false, err
+                       }
+               }
+
+               unmounted = true
+       }
+}
+
+func sameMount(srcPath string, dstPath string) bool {
+       // Get the source vfs path information
+       var srcFsStat unix.Statfs_t
+       err := unix.Statfs(srcPath, &srcFsStat)
+       if err != nil {
+               return false
+       }
+
+       // Get the destination vfs path information
+       var dstFsStat unix.Statfs_t
+       err = unix.Statfs(dstPath, &dstFsStat)
+       if err != nil {
+               return false
+       }
+
+       // Compare statfs
+       if srcFsStat.Type != dstFsStat.Type || srcFsStat.Fsid != dstFsStat.Fsid 
{
+               return false
+       }
+
+       // Get the source path information
+       var srcStat unix.Stat_t
+       err = unix.Stat(srcPath, &srcStat)
+       if err != nil {
+               return false
+       }
+
+       // Get the destination path information
+       var dstStat unix.Stat_t
+       err = unix.Stat(dstPath, &dstStat)
+       if err != nil {
+               return false
+       }
+
+       // Compare inode
+       if srcStat.Ino != dstStat.Ino {
+               return false
+       }
+
+       return true
+}
+
+func tryMount(src string, dst string, fs string, flags uintptr, options 
string) error {
+       var err error
+
+       // Attempt 20 mounts over 10s
+       for i := 0; i < 20; i++ {
+               err = unix.Mount(src, dst, fs, flags, options)
+               if err == nil {
+                       break
+               }
+
+               time.Sleep(500 * time.Millisecond)
+       }
+
+       if err != nil {
+               return err
+       }
+
+       return nil
+}
+
+func vfsResources(path string) (*api.ResourcesStoragePool, error) {
+       // Get the VFS information
+       st, err := shared.Statvfs(path)
+       if err != nil {
+               return nil, err
+       }
+
+       // Fill in the struct
+       res := api.ResourcesStoragePool{}
+       res.Space.Total = st.Blocks * uint64(st.Bsize)
+       res.Space.Used = (st.Blocks - st.Bfree) * uint64(st.Bsize)
+
+       // Some filesystems don't report inodes since they allocate them
+       // dynamically e.g. btrfs.
+       if st.Files > 0 {
+               res.Inodes.Total = st.Files
+               res.Inodes.Used = st.Files - st.Ffree
+       }
+
+       return &res, nil
+}

From 91b1e41b787a796db5c309f06465c61657a8b6a4 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 10 Oct 2019 12:08:08 +0100
Subject: [PATCH 2/6] lxd/storage/drivers/utils: Adds GetVolumeMountPoint and
 GetPoolMountPoint functions

- Adds tests for GetVolumeMountPoint

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/utils.go      | 19 ++++++++++++++++
 lxd/storage/drivers/utils_test.go | 37 +++++++++++++++++++++++++++++++
 2 files changed, 56 insertions(+)
 create mode 100644 lxd/storage/drivers/utils_test.go

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index e0cf6ce803..8887643431 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -1,6 +1,7 @@
 package drivers
 
 import (
+       "fmt"
        "io/ioutil"
        "os"
        "path/filepath"
@@ -8,6 +9,7 @@ import (
 
        "golang.org/x/sys/unix"
 
+       "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/api"
 )
@@ -139,3 +141,20 @@ func vfsResources(path string) (*api.ResourcesStoragePool, 
error) {
 
        return &res, nil
 }
+
+// GetPoolMountPoint returns the mountpoint of the given pool.
+// {LXD_DIR}/storage-pools/<pool>
+func GetPoolMountPoint(poolName string) string {
+       return shared.VarPath("storage-pools", poolName)
+}
+
+// GetVolumeMountPoint returns the mount path for a specific volume based on 
its pool and type and
+// whether it is a snapshot or not.
+// For VolumeTypeImage the volName is the image fingerprint.
+func GetVolumeMountPoint(poolName string, volType VolumeType, volName string) 
string {
+       if shared.IsSnapshot(volName) {
+               return shared.VarPath("storage-pools", poolName, 
fmt.Sprintf("%s-snapshots", string(volType)), project.Prefix("default", 
volName))
+       }
+
+       return shared.VarPath("storage-pools", poolName, string(volType), 
project.Prefix("default", volName))
+}
diff --git a/lxd/storage/drivers/utils_test.go 
b/lxd/storage/drivers/utils_test.go
new file mode 100644
index 0000000000..b2c358a501
--- /dev/null
+++ b/lxd/storage/drivers/utils_test.go
@@ -0,0 +1,37 @@
+package drivers
+
+import (
+       "testing"
+
+       "github.com/stretchr/testify/assert"
+)
+
+// Test GetVolumeMountPoint
+func TestGetVolumeMountPoint(t *testing.T) {
+       poolName := "testpool"
+
+       // Test custom volume.
+       path := GetVolumeMountPoint(poolName, VolumeTypeCustom, "testvol")
+       expected := GetPoolMountPoint(poolName) + "/custom/testvol"
+       assert.Equal(t, expected, path)
+
+       // Test custom volume snapshot.
+       path = GetVolumeMountPoint(poolName, VolumeTypeCustom, "testvol/snap1")
+       expected = GetPoolMountPoint(poolName) + 
"/custom-snapshots/testvol/snap1"
+       assert.Equal(t, expected, path)
+
+       // Test image volume.
+       path = GetVolumeMountPoint(poolName, VolumeTypeImage, "fingerprint")
+       expected = GetPoolMountPoint(poolName) + "/images/fingerprint"
+       assert.Equal(t, expected, path)
+
+       // Test container volume.
+       path = GetVolumeMountPoint(poolName, VolumeTypeContainer, "testvol")
+       expected = GetPoolMountPoint(poolName) + "/containers/testvol"
+       assert.Equal(t, expected, path)
+
+       // Test virtual-machine volume.
+       path = GetVolumeMountPoint(poolName, VolumeTypeVM, "testvol")
+       expected = GetPoolMountPoint(poolName) + "/virtual-machines/testvol"
+       assert.Equal(t, expected, path)
+}

From a2a63d0b63cec218e39d2c735ed37470a5ac07c5 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 15 Oct 2019 09:30:28 +0100
Subject: [PATCH 3/6] lxd/storage/drivers/utils: Adds
 DeleteParentSnapshotDirIfEmpty

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/utils.go | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index 8887643431..7875e20ec4 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -5,6 +5,7 @@ import (
        "io/ioutil"
        "os"
        "path/filepath"
+       "strings"
        "time"
 
        "golang.org/x/sys/unix"
@@ -158,3 +159,30 @@ func GetVolumeMountPoint(poolName string, volType 
VolumeType, volName string) st
 
        return shared.VarPath("storage-pools", poolName, string(volType), 
project.Prefix("default", volName))
 }
+
+// DeleteParentSnapshotDirIfEmpty removes the parent snapshot directory if it 
is empty.
+// It accepts the volume name of a snapshot in the form "volume/snap" and the 
volume path of the
+// snapshot. It will then remove the snapshots directory above "/snap" if it 
is empty.
+func DeleteParentSnapshotDirIfEmpty(volName string, volPath string) error {
+       _, snapName, isSnap := shared.ContainerGetParentAndSnapshotName(volName)
+       if !isSnap {
+               return fmt.Errorf("Volume is not a snapshot")
+       }
+
+       // Extract just the snapshot name from the volume name and then remove 
that suffix
+       // from the volume path. This will get us the parent snapshots 
directory we need.
+       snapshotsPath := strings.TrimSuffix(volPath, snapName)
+       isEmpty, err := shared.PathIsEmpty(snapshotsPath)
+       if err != nil {
+               return err
+       }
+
+       if isEmpty {
+               err := os.Remove(snapshotsPath)
+               if err != nil {
+                       return err
+               }
+       }
+
+       return nil
+}

From 86fda731ed974dd36e29b88260dc7bd5c77af0de Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 15 Oct 2019 12:11:57 +0100
Subject: [PATCH 4/6] lxd/storage/drivers/utils: Add GetVolumeSnapshotDir

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/utils.go | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lxd/storage/drivers/utils.go b/lxd/storage/drivers/utils.go
index 7875e20ec4..9fa811ff86 100644
--- a/lxd/storage/drivers/utils.go
+++ b/lxd/storage/drivers/utils.go
@@ -160,6 +160,15 @@ func GetVolumeMountPoint(poolName string, volType 
VolumeType, volName string) st
        return shared.VarPath("storage-pools", poolName, string(volType), 
project.Prefix("default", volName))
 }
 
+// GetVolumeSnapshotDir gets the snapshot mount directory for the parent 
volume.
+func GetVolumeSnapshotDir(poolName string, volType VolumeType, volName string) 
(string, error) {
+       if shared.IsSnapshot(volName) {
+               return "", fmt.Errorf("Volume cannot be a snapshot")
+       }
+
+       return shared.VarPath("storage-pools", poolName, 
fmt.Sprintf("%s-snapshots", string(volType)), project.Prefix("default", 
volName)), nil
+}
+
 // DeleteParentSnapshotDirIfEmpty removes the parent snapshot directory if it 
is empty.
 // It accepts the volume name of a snapshot in the form "volume/snap" and the 
volume path of the
 // snapshot. It will then remove the snapshots directory above "/snap" if it 
is empty.

From 11fd61a6ca700a94cf12a0c6a4d2af6693df01bf Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Tue, 22 Oct 2019 15:43:37 +0100
Subject: [PATCH 5/6] lxd/storage/drivers/volume: Adds VolumeType and
 ContentType definitions

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/drivers/volume.go | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)
 create mode 100644 lxd/storage/drivers/volume.go

diff --git a/lxd/storage/drivers/volume.go b/lxd/storage/drivers/volume.go
new file mode 100644
index 0000000000..0bd76110cc
--- /dev/null
+++ b/lxd/storage/drivers/volume.go
@@ -0,0 +1,26 @@
+package drivers
+
+// VolumeType represents a storage volume type.
+type VolumeType string
+
+// VolumeTypeImage represents an image storage volume.
+const VolumeTypeImage = VolumeType("images")
+
+// VolumeTypeCustom represents a custom storage volume.
+const VolumeTypeCustom = VolumeType("custom")
+
+// VolumeTypeContainer represents a container storage volume.
+const VolumeTypeContainer = VolumeType("containers")
+
+// VolumeTypeVM represents a virtual-machine storage volume.
+const VolumeTypeVM = VolumeType("virtual-machines")
+
+// ContentType indicates the format of the volume.
+type ContentType string
+
+// ContentTypeFS indicates the volume will be populated with a mountabble 
filesystem.
+const ContentTypeFS = ContentType("fs")
+
+// ContentTypeBlock indicates the volume will be a block device and its 
contents and we do not
+// know which filesystem(s) (if any) are in use.
+const ContentTypeBlock = ContentType("block")

From a0668d084f7e57a60cb416fe9b02639a53bf0004 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Thu, 10 Oct 2019 12:13:50 +0100
Subject: [PATCH 6/6] lxd/storage/storage: Deprecates pool path function

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/storage/storage.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/storage/storage.go b/lxd/storage/storage.go
index b8d8d42b31..2f2e9aec13 100644
--- a/lxd/storage/storage.go
+++ b/lxd/storage/storage.go
@@ -18,6 +18,7 @@ func ContainerPath(name string, isSnapshot bool) string {
 
 // GetStoragePoolMountPoint returns the mountpoint of the given pool.
 // {LXD_DIR}/storage-pools/<pool>
+// Deprecated, use GetPoolMountPoint in storage/drivers package.
 func GetStoragePoolMountPoint(poolName string) string {
        return shared.VarPath("storage-pools", poolName)
 }
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to