-
Notifications
You must be signed in to change notification settings - Fork 18
/
driver.go
242 lines (218 loc) · 10.6 KB
/
driver.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
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/*
Copyright 2021 NetApp, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0.
*/
package driver
import (
"context"
"path"
beegfsv1 "github.com/netapp/beegfs-csi-driver/operator/api/v1"
"github.com/netapp/beegfs-csi-driver/pkg/beegfs"
corev1 "k8s.io/api/core/v1"
storagev1 "k8s.io/api/storage/v1"
"k8s.io/apimachinery/pkg/util/sets"
e2eframework "k8s.io/kubernetes/test/e2e/framework"
e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
storageframework "k8s.io/kubernetes/test/e2e/storage/framework"
)
// Verify expected interfaces are properly implemented at compile time.
var _ storageframework.TestDriver = &BeegfsDriver{}
var _ storageframework.TestDriver = &BeegfsDynamicDriver{}
var _ storageframework.DynamicPVTestDriver = &BeegfsDriver{}
var _ storageframework.DynamicPVTestDriver = &BeegfsDynamicDriver{}
var _ storageframework.PreprovisionedVolumeTestDriver = &BeegfsDriver{}
// baseBeegfsDriver is unexported and cannot be directly accessed or instantiated. All exported drivers use it as
// their underlying data structure and can call its internal methods.
type baseBeegfsDriver struct {
driverInfo storageframework.DriverInfo
perFSConfigs []beegfsv1.FileSystemSpecificConfig
fsIndex int
extraSCParams map[string]string
dynamicVolDirBasePathBeegfsRoot string // Set once on initialization (e.g. /e2e-test/dynamic).
staticVolDirPathBeegfsRoot string // Set once on initialization (e.g. /e2e-test/static/static1).
}
// BeegfsDriver is an exported driver that implements the storageframework.TestDriver,
// storageframework.DynamicPVTestDriver, storageframework.PreprovisionedVolumeTestDriver, and
// storageframework.PreprovisionedPVTestDriver interfaces. It is intended to be used in all beegfs-csi-driver specific
// tests.
type BeegfsDriver struct {
*baseBeegfsDriver
}
// BeegfsDynamicDriver is an exported driver that implements the storageframework.TestDriver and
// storageframework.DynamicPVTestDriver interfaces. It intentionally does not implement the
// storageframework.PreprovisionedVolumeTestDriver and storageframework.PreprovisionedPVTestDriver interfaces. It is
// intended to be used for K8s built-in tests, which may use the pre-provisioned interface in unanticipated ways if
// allowed.
type BeegfsDynamicDriver struct {
*baseBeegfsDriver
}
// GetDriverInfo is part of the storageframework.TestDriver interface.
func (d *baseBeegfsDriver) GetDriverInfo() *storageframework.DriverInfo {
return &d.driverInfo
}
// SkipUnsupportedTest is part of the storageframework.TestDriver interface.
func (d *baseBeegfsDriver) SkipUnsupportedTest(pattern storageframework.TestPattern) {
if pattern.VolType == storageframework.PreprovisionedPV && d.staticVolDirPathBeegfsRoot == "" {
e2eskipper.Skipf("Set staticVolDirPathBeegfsRoot to enable pre-provisioned tests -- skipping")
}
}
// PrepareTest is part of the storageframework.TestDriver interface.
func (d *baseBeegfsDriver) PrepareTest(ctx context.Context, f *e2eframework.Framework) *storageframework.PerTestConfig {
config := &storageframework.PerTestConfig{
Driver: d,
Prefix: "beegfs",
Framework: f,
}
return config
}
// initBaseBeegfsDriver handles basic initialization shared across all exported drivers.
func initBaseBeegfsDriver(dynamicVolDirBasePathBeegfsRoot, staticVolDirPathBeegfsRoot string) *baseBeegfsDriver {
return &baseBeegfsDriver{
driverInfo: storageframework.DriverInfo{
Name: "beegfs",
// FeatureTag:
// MaxFileSize:
// SupportedSizeRange:
SupportedFsType: sets.NewString(""),
// This list of supported mount options is non-exhaustive - there may be other valid mount options such as
// "ro", but this is only the list of mount options we choose to test
SupportedMountOption: sets.NewString("rw", "relatime", "noexec"),
Capabilities: map[storageframework.Capability]bool{
storageframework.CapPersistence: true,
storageframework.CapBlock: false,
storageframework.CapFsGroup: false,
storageframework.CapExec: true,
storageframework.CapSnapshotDataSource: false,
storageframework.CapPVCDataSource: false,
storageframework.CapMultiPODs: true,
storageframework.CapRWX: true,
storageframework.CapControllerExpansion: false,
storageframework.CapNodeExpansion: false,
storageframework.CapVolumeLimits: false,
// This setting is only used in two places, both in the multivolume test suite. Setting this to true
// signals that we *only* support single-node volumes and should skip tests that require a volume to
// be shared between two different nodes.
storageframework.CapSingleNodeVolume: false,
storageframework.CapTopology: false,
},
// RequiredAccessModes:
// TopologyKeys:
// NumAllowedTopologies:
StressTestOptions: &storageframework.StressTestOptions{
NumPods: 10,
NumRestarts: 3,
},
// VolumeSnapshotStressTestOptions:
},
perFSConfigs: make([]beegfsv1.FileSystemSpecificConfig, 0),
fsIndex: 0,
dynamicVolDirBasePathBeegfsRoot: dynamicVolDirBasePathBeegfsRoot,
staticVolDirPathBeegfsRoot: staticVolDirPathBeegfsRoot,
}
}
// InitBeegfsDriver returns a pointer to a BeegfsDriver.
func InitBeegfsDriver(dynamicVolDirBasePathBeegfsRoot, staticVolDirBasePathBeegfsRoot,
staticVolDirName string) *BeegfsDriver {
staticVolDirPathBeegfsRoot := ""
if staticVolDirBasePathBeegfsRoot != "" && staticVolDirName != "" {
staticVolDirPathBeegfsRoot = path.Join(staticVolDirBasePathBeegfsRoot, staticVolDirName)
}
return &BeegfsDriver{baseBeegfsDriver: initBaseBeegfsDriver(dynamicVolDirBasePathBeegfsRoot,
staticVolDirPathBeegfsRoot)}
}
// InitBeegfsDynamicDriver returns a pointer to a BeegfsDynamicDriver.
func InitBeegfsDynamicDriver(dynamicVolDirBasePathBeegfsRoot string) *BeegfsDynamicDriver {
return &BeegfsDynamicDriver{baseBeegfsDriver: initBaseBeegfsDriver(dynamicVolDirBasePathBeegfsRoot, "")}
}
// GetDynamicProvisionStorageClass is part of the storageframework.DynamicPVTestDriver interface.
func (d *baseBeegfsDriver) GetDynamicProvisionStorageClass(ctx context.Context, config *storageframework.PerTestConfig,
fsType string) *storagev1.StorageClass {
params := map[string]string{
"sysMgmtdHost": d.perFSConfigs[d.fsIndex].SysMgmtdHost,
"volDirBasePath": d.dynamicVolDirBasePathBeegfsRoot,
}
if d.extraSCParams != nil {
for k, v := range d.extraSCParams {
params[k] = v
}
}
// Do not explicitly set volumeBindingMode. By default, this results in VolumeBindingImmediate behavior. Framework
// functions overwrite volumeBindingMode from storageframework.TestPattern as needed.
return storageframework.GetStorageClass("beegfs.csi.netapp.com", params, nil, config.Framework.Namespace.Name)
}
// CreateVolume is part of the storageframework.PreprovisionedVolumeTestDriver interface.
// CreateVolume returns a storageframework.TestVolume that appropriately references a pre-created directory on a
// BeeGFS file system known to the driver. Tests can use SetFSIndex and SetStaticDirName to modify its behavior.
func (d *BeegfsDriver) CreateVolume(ctx context.Context, config *storageframework.PerTestConfig, volumeType storageframework.TestVolType) storageframework.TestVolume {
fsConfig := d.perFSConfigs[d.fsIndex]
return beegfsVolume{
volumeID: beegfs.NewBeegfsURL(fsConfig.SysMgmtdHost, d.staticVolDirPathBeegfsRoot),
}
}
// GetPersistentVolumeSource is part of the storageframework.PreprovisionedPVTestDriver interface.
// GetPersistentVolumeSource returns a PersistentVolumeSource that appropriately references a pre-created directory
// on a BeeGFS file system known to the driver.
func (d *BeegfsDriver) GetPersistentVolumeSource(readOnly bool, fsType string,
testVolume storageframework.TestVolume) (*corev1.PersistentVolumeSource, *corev1.VolumeNodeAffinity) {
beegfsVol := testVolume.(beegfsVolume) // Assert that we have a beegfsVolume.
csiSource := corev1.CSIPersistentVolumeSource{
Driver: "beegfs.csi.netapp.com",
VolumeHandle: beegfsVol.volumeID,
ReadOnly: readOnly,
FSType: fsType,
}
volumeSource := corev1.PersistentVolumeSource{
CSI: &csiSource,
}
return &volumeSource, nil
}
// SetStorageClassParams injects additional parameters into the driver. These parameters will appear in all
// generated StorageClasses until UnsetStorageClassParams() is called.
func (d *baseBeegfsDriver) SetStorageClassParams(extraSCParams map[string]string) {
d.extraSCParams = extraSCParams
}
// UnsetStorageClassParams reverses SetStorageClassParams.
func (d *baseBeegfsDriver) UnsetStorageClassParams() {
d.extraSCParams = nil
}
// SetFSIndex determines which PerFSConfig will be used for various volume provisioning related tasks. It intentionally
// has no internal error correction. Use GetNumFS to determine the maximum fsIndex to set. If you set fsIndex above the
// maximum, tests will fail.
func (d *baseBeegfsDriver) SetFSIndex(fsIndex int) {
d.fsIndex = fsIndex
}
// GetNumFS returns the maximum fsIndex that should be used with setFSIndex. It may also be useful in skipping certain
// beegfs-csi-driver specific tests (e.g. a test that requires two different file systems should be skipped if
// GetNumFS returns 1.
func (d *baseBeegfsDriver) GetNumFS() int {
return len(d.perFSConfigs)
}
// SetFSIndexForRDMA looks for an RDMA capable file system and sets fsIndex to refer to the first one it finds. It
// returns false if there are no RDMA capable file systems.
func (d *baseBeegfsDriver) SetFSIndexForRDMA() bool {
for i, cfg := range d.perFSConfigs {
if boolString, ok := cfg.Config.BeegfsClientConf["connUseRDMA"]; ok {
if boolString == "true" {
d.SetFSIndex(i)
return true
}
}
}
return false // There are no RDMA capable file systems.
}
// SetPerFSConfigs sets perFSConfigs from a slice of beegfs.FileSystemSpecificConfigs.
func (d *baseBeegfsDriver) SetPerFSConfigs(perFSConfigs []beegfsv1.FileSystemSpecificConfig) {
d.perFSConfigs = perFSConfigs
}
// beegfsVolume implements the storageframework.TestVolume interface.
// The end-to-end Kubernetes tests and various framework functions expect to handle a storageframework.TestVolume that
// knows how to delete itself (out-of-band of a running CSI driver).
type beegfsVolume struct {
volumeID string // pkg/beegfs.beegfsVolume.volumeID
}
// DeleteVolume is part of the storageframework.TestVolume interface.
// We don't actually do anything when DeleteVolume() is called.
func (v beegfsVolume) DeleteVolume(ctx context.Context) {
// Intentionally empty.
// Our pre-provisioned volumes are not created on demand and are not deleted at the end of a test.
}