Skip to content

Commit 0080a77

Browse files
committed
feat: support NFS storage pools
Signed-off-by: Morten Linderud <[email protected]>
1 parent 62c95e9 commit 0080a77

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package drivers
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/lxc/incus/v6/internal/linux"
8+
"github.com/lxc/incus/v6/internal/migration"
9+
deviceConfig "github.com/lxc/incus/v6/internal/server/device/config"
10+
localMigration "github.com/lxc/incus/v6/internal/server/migration"
11+
"github.com/lxc/incus/v6/shared/util"
12+
)
13+
14+
type nfs struct {
15+
dir
16+
}
17+
18+
// Info returns info about the driver and its environment.
19+
func (n *nfs) Info() Info {
20+
return Info{
21+
Name: "nfs",
22+
Version: "1",
23+
DefaultVMBlockFilesystemSize: deviceConfig.DefaultVMBlockFilesystemSize,
24+
OptimizedImages: false,
25+
PreservesInodes: false,
26+
Remote: n.isRemote(),
27+
VolumeTypes: []VolumeType{VolumeTypeCustom, VolumeTypeContainer, VolumeTypeVM},
28+
VolumeMultiNode: n.isRemote(),
29+
BlockBacking: false,
30+
RunningCopyFreeze: false,
31+
DirectIO: true,
32+
MountedRoot: true,
33+
Buckets: false,
34+
}
35+
}
36+
37+
// isRemote returns true indicating this driver uses remote storage.
38+
func (n *nfs) isRemote() bool {
39+
return true
40+
}
41+
42+
func (n *nfs) getMountOptions() string {
43+
// Allow overriding the default options.
44+
if n.config["nfs.mount_options"] != "" {
45+
return n.config["nfs.mount_options"]
46+
}
47+
// We only really support vers=4.2
48+
return "vers=4.2,addr=" + n.config["nfs.addr"]
49+
}
50+
51+
// Create is called during pool creation and is effectively using an empty driver struct.
52+
// WARNING: The Create() function cannot rely on any of the struct attributes being set.
53+
func (n *nfs) Create() error {
54+
if n.config["source"] != "" {
55+
return fmt.Errorf(`The "source" property must be defined`)
56+
}
57+
58+
// We are dealing with IPv4 or IPv6, assume the last occurrence of : splits between the network addr and the mount path
59+
s := strings.LastIndex(n.config["source"], ":")
60+
61+
// URI should be first part of IP:PORT
62+
n.config["nfs.addr"] = n.config["source"][:s]
63+
64+
// nfs.path is the NFS path we pass to mount
65+
n.config["nfs.path"] = n.config["source"]
66+
67+
// Mount the nfs driver.
68+
mntFlags, mntOptions := linux.ResolveMountOptions(strings.Split(n.getMountOptions(), ","))
69+
err := TryMount(n.config["nfs.path"], GetPoolMountPath(n.name), "nfs4", mntFlags, mntOptions)
70+
if err != nil {
71+
return err
72+
}
73+
74+
defer func() { _, _ = forceUnmount(GetPoolMountPath(n.name)) }()
75+
76+
return nil
77+
}
78+
79+
// Mount mounts the storage pool.
80+
func (n *nfs) Mount() (bool, error) {
81+
path := GetPoolMountPath(n.name)
82+
83+
// Check if already mounted.
84+
if linux.IsMountPoint(path) {
85+
return false, nil
86+
}
87+
88+
sourcePath := n.config["nfs.path"]
89+
90+
// Check if we're dealing with an external mount.
91+
if sourcePath == path {
92+
return false, nil
93+
}
94+
95+
// Mount the nfs driver.
96+
mntFlags, mntOptions := linux.ResolveMountOptions(strings.Split(n.getMountOptions(), ","))
97+
err := TryMount(sourcePath, GetPoolMountPath(n.name), "nfs4", mntFlags, mntOptions)
98+
if err != nil {
99+
return false, err
100+
}
101+
102+
return true, nil
103+
}
104+
105+
// MigrationTypes returns the type of transfer methods to be used when doing migrations between pools in preference order.
106+
func (n *nfs) MigrationTypes(contentType ContentType, refresh bool, copySnapshots bool, clusterMove bool, storageMove bool) []localMigration.Type {
107+
// NFS does not support xattr
108+
rsyncFeatures := []string{"delete", "bidirectional"}
109+
if util.IsTrue(n.Config()["rsync.compression"]) {
110+
rsyncFeatures = append(rsyncFeatures, "compress")
111+
}
112+
113+
return []localMigration.Type{
114+
{
115+
FSType: migration.MigrationFSType_BLOCK_AND_RSYNC,
116+
Features: rsyncFeatures,
117+
},
118+
{
119+
FSType: migration.MigrationFSType_RSYNC,
120+
Features: rsyncFeatures,
121+
},
122+
}
123+
}

internal/server/storage/drivers/load.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ var drivers = map[string]func() driver{
1616
"truenas": func() driver { return &truenas{} },
1717
"zfs": func() driver { return &zfs{} },
1818
"linstor": func() driver { return &linstor{} },
19+
"nfs": func() driver { return &nfs{} },
1920
}
2021

2122
// Validators contains functions used for validating a drivers's config.

0 commit comments

Comments
 (0)