-
Notifications
You must be signed in to change notification settings - Fork 94
/
mount.go
210 lines (178 loc) · 5.4 KB
/
mount.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package zfs
import (
"fmt"
"os"
"github.com/Sirupsen/logrus"
apis "github.com/openebs/zfs-localpv/pkg/apis/openebs.io/zfs/v1alpha1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"k8s.io/kubernetes/pkg/util/mount"
)
// FormatAndMountZvol formats and mounts the created volume to the desired mount path
func FormatAndMountZvol(devicePath string, mountInfo *apis.MountInfo) error {
mounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: mount.NewOsExec()}
err := mounter.FormatAndMount(devicePath, mountInfo.MountPath, mountInfo.FSType, mountInfo.MountOptions)
if err != nil {
logrus.Errorf(
"zfspv: failed to mount volume %s [%s] to %s, error %v",
devicePath, mountInfo.FSType, mountInfo.MountPath, err,
)
return err
}
return nil
}
// UmountVolume unmounts the volume and the corresponding mount path is removed
func UmountVolume(vol *apis.ZFSVolume, targetPath string,
) error {
mounter := &mount.SafeFormatAndMount{Interface: mount.New(""), Exec: mount.NewOsExec()}
_, _, err := mount.GetDeviceNameFromMount(mounter, targetPath)
if err != nil {
logrus.Errorf(
"zfspv umount volume: failed to get device from mnt: %s\nError: %v",
targetPath, err,
)
return err
}
if pathExists, pathErr := mount.PathExists(targetPath); pathErr != nil {
return fmt.Errorf("Error checking if path exists: %v", pathErr)
} else if !pathExists {
logrus.Warningf(
"Warning: Unmount skipped because path does not exist: %v",
targetPath,
)
return nil
}
if vol.Spec.VolumeType == VOLTYPE_DATASET {
if err = UmountZFSDataset(vol); err != nil {
logrus.Errorf(
"zfspv failed to umount dataset: path %s Error: %v",
targetPath, err,
)
return err
}
} else {
if err = mounter.Unmount(targetPath); err != nil {
logrus.Errorf(
"zfspv failed to unmount zvol: path %s Error: %v",
targetPath, err,
)
return err
}
}
if err := os.RemoveAll(targetPath); err != nil {
logrus.Errorf("zfspv: failed to remove mount path Error: %v", err)
return err
}
logrus.Infof("umount done path %v", targetPath)
return nil
}
// GetMounts gets mountpoints for the specified volume
func GetMounts(dev string) ([]string, error) {
var (
currentMounts []string
err error
mountList []mount.MountPoint
)
mounter := mount.New("")
// Get list of mounted paths present with the node
if mountList, err = mounter.List(); err != nil {
return nil, err
}
for _, mntInfo := range mountList {
if mntInfo.Device == dev {
currentMounts = append(currentMounts, mntInfo.Path)
}
}
return currentMounts, nil
}
// IsMountPath returns true if path is a mount path
func IsMountPath(path string) bool {
var (
err error
mountList []mount.MountPoint
)
mounter := mount.New("")
// Get list of mounted paths present with the node
if mountList, err = mounter.List(); err != nil {
return false
}
for _, mntInfo := range mountList {
if mntInfo.Path == path {
return true
}
}
return false
}
func verifyMountRequest(vol *apis.ZFSVolume, mountpath string) error {
if len(mountpath) == 0 {
return status.Error(codes.InvalidArgument, "mount path missing in request")
}
if len(vol.Spec.OwnerNodeID) > 0 &&
vol.Spec.OwnerNodeID != NodeID {
return status.Error(codes.Internal, "volume is owned by different node")
}
devicePath, err := GetVolumeDevPath(vol)
if err != nil {
logrus.Errorf("can not get device for volume:%s dev %s err: %v",
vol.Name, devicePath, err.Error())
return err
}
/*
* This check is the famous *Wall Of North*
* It will not let the volume to be mounted
* at more than two places. The volume should
* be unmounted before proceeding to the mount
* operation.
*/
currentMounts, err := GetMounts(devicePath)
if err != nil {
logrus.Errorf("can not get mounts for volume:%s dev %s err: %v",
vol.Name, devicePath, err.Error())
return err
} else if len(currentMounts) >= 1 {
logrus.Errorf(
"can not mount, volume:%s already mounted dev %s mounts: %v",
vol.Name, devicePath, currentMounts,
)
return status.Error(codes.Internal, "device already mounted")
}
return nil
}
// MountZvol mounts the disk to the specified path
func MountZvol(vol *apis.ZFSVolume, mount *apis.MountInfo) error {
volume := vol.Spec.PoolName + "/" + vol.Name
err := verifyMountRequest(vol, mount.MountPath)
if err != nil {
return status.Error(codes.Internal, "zvol can not be mounted")
}
devicePath := ZFS_DEVPATH + volume
err = FormatAndMountZvol(devicePath, mount)
if err != nil {
return status.Error(codes.Internal, "not able to format and mount the zvol")
}
logrus.Infof("zvol %v mounted %v fs %v", volume, mount.MountPath, mount.FSType)
return err
}
// MountDataset mounts the zfs dataset to the specified path
func MountDataset(vol *apis.ZFSVolume, mount *apis.MountInfo) error {
volume := vol.Spec.PoolName + "/" + vol.Name
err := verifyMountRequest(vol, mount.MountPath)
if err != nil {
return status.Error(codes.Internal, "dataset can not be mounted")
}
err = MountZFSDataset(vol, mount.MountPath)
if err != nil {
return status.Error(codes.Internal, "not able to mount the dataset")
}
logrus.Infof("dataset %v mounted %v", volume, mount.MountPath)
return nil
}
// MountVolume mounts the disk to the specified path
func MountVolume(vol *apis.ZFSVolume, mount *apis.MountInfo) error {
switch vol.Spec.VolumeType {
case VOLTYPE_DATASET:
return MountDataset(vol, mount)
default:
return MountZvol(vol, mount)
}
}