Skip to content

Commit 0e94a80

Browse files
authored
Merge pull request #498 from andyzhangx/create-subdir-if-not-exists
feat: create subdir if not exists
2 parents 2457c6d + 8e74fa3 commit 0e94a80

File tree

7 files changed

+180
-97
lines changed

7 files changed

+180
-97
lines changed

docs/driver-parameters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
Name | Meaning | Available Value | Mandatory | Default value
77
--- | --- | --- | --- | ---
88
source | Samba Server address | `//smb-server-address/sharename` </br>([Azure File](https://docs.microsoft.com/en-us/azure/storage/files/storage-files-introduction) format: `//accountname.file.core.windows.net/filesharename`) | Yes |
9-
subDir | existing sub directory under smb share | | No | sub directory must exist otherwise mount would fail
9+
subDir | sub directory under smb share | | No | if sub directory does not exist, this driver would create a new one
1010
csi.storage.k8s.io/provisioner-secret-name | secret name that stores `username`, `password`(`domain` is optional); if secret is provided, driver will create a sub directory with PV name under `source` | existing secret name | No |
1111
csi.storage.k8s.io/provisioner-secret-namespace | namespace where the secret is | existing secret namespace | No |
1212
csi.storage.k8s.io/node-stage-secret-name | secret name that stores `username`, `password`(`domain` is optional) | existing secret name | Yes |

pkg/smb/controllerserver.go

Lines changed: 45 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ type smbVolume struct {
3939
// Volume id
4040
id string
4141
// Address of the SMB server.
42-
sourceField string
42+
source string
4343
// Subdirectory of the SMB server to create volumes under
4444
subDir string
4545
// size of volume
@@ -51,7 +51,7 @@ type smbVolume struct {
5151
// Ordering of elements in the CSI volume id.
5252
// ID is of the form {server}/{subDir}.
5353
const (
54-
idsourceField = iota
54+
idSource = iota
5555
idSubDir
5656
idUUID
5757
totalIDElements // Always last
@@ -81,8 +81,8 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
8181
secrets := req.GetSecrets()
8282
createSubDir := len(secrets) > 0
8383
if len(smbVol.uuid) > 0 {
84-
klog.V(2).Infof("existing subDir(%s) is provided, skip subdirectory creation", smbVol.subDir)
85-
createSubDir = false
84+
klog.V(2).Infof("create subdirectory(%s) if not exists", smbVol.subDir)
85+
createSubDir = true
8686
}
8787

8888
volCap := volumeCapabilities[0]
@@ -106,11 +106,11 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
106106
}()
107107
// Create subdirectory under base-dir
108108
// TODO: revisit permissions
109-
internalVolumePath := d.getInternalVolumePath(smbVol)
109+
internalVolumePath := getInternalVolumePath(d.workingMountDir, smbVol)
110110
if err = os.Mkdir(internalVolumePath, 0777); err != nil && !os.IsExist(err) {
111111
return nil, status.Errorf(codes.Internal, "failed to make subdirectory: %v", err.Error())
112112
}
113-
parameters[subDirField] = smbVol.subDir
113+
setKeyValueInMap(parameters, subDirField, smbVol.subDir)
114114
} else {
115115
klog.V(2).Infof("CreateVolume(%s) does not create subdirectory", name)
116116
}
@@ -145,10 +145,6 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
145145

146146
secrets := req.GetSecrets()
147147
deleteSubDir := len(secrets) > 0
148-
if len(smbVol.uuid) > 0 {
149-
klog.V(2).Infof("existing subDir(%s) is provided, skip subdirectory deletion", smbVol.subDir)
150-
deleteSubDir = false
151-
}
152148
if !deleteSubDir {
153149
options := strings.Split(mountOptions, ",")
154150
if hasGuestMountOptions(options) {
@@ -169,7 +165,7 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
169165
}()
170166

171167
// Delete subdirectory under base-dir
172-
internalVolumePath := d.getInternalVolumePath(smbVol)
168+
internalVolumePath := getInternalVolumePath(d.workingMountDir, smbVol)
173169
klog.V(2).Infof("Removing subdirectory at %v", internalVolumePath)
174170
if err = os.RemoveAll(internalVolumePath); err != nil {
175171
return nil, status.Errorf(codes.Internal, "failed to delete subdirectory: %v", err.Error())
@@ -244,23 +240,9 @@ func (d *Driver) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsReques
244240
return nil, status.Error(codes.Unimplemented, "")
245241
}
246242

247-
// Given a smbVolume, return a CSI volume id
248-
func getVolumeIDFromSmbVol(vol *smbVolume) string {
249-
idElements := make([]string, totalIDElements)
250-
idElements[idsourceField] = strings.Trim(vol.sourceField, "/")
251-
idElements[idSubDir] = strings.Trim(vol.subDir, "/")
252-
idElements[idUUID] = vol.uuid
253-
return strings.Join(idElements, separator)
254-
}
255-
256-
// Get working directory for CreateVolume and DeleteVolume
257-
func (d *Driver) getInternalMountPath(vol *smbVolume) string {
258-
return filepath.Join(d.workingMountDir, vol.subDir)
259-
}
260-
261243
// Mount smb server at base-dir
262244
func (d *Driver) internalMount(ctx context.Context, vol *smbVolume, volCap *csi.VolumeCapability, secrets map[string]string) error {
263-
stagingPath := d.getInternalMountPath(vol)
245+
stagingPath := getInternalMountPath(d.workingMountDir, vol)
264246

265247
if volCap == nil {
266248
volCap = &csi.VolumeCapability{
@@ -270,11 +252,11 @@ func (d *Driver) internalMount(ctx context.Context, vol *smbVolume, volCap *csi.
270252
}
271253
}
272254

273-
klog.V(4).Infof("internally mounting %v at %v", sourceField, stagingPath)
255+
klog.V(4).Infof("internally mounting %v at %v", vol.source, stagingPath)
274256
_, err := d.NodeStageVolume(ctx, &csi.NodeStageVolumeRequest{
275257
StagingTargetPath: stagingPath,
276258
VolumeContext: map[string]string{
277-
sourceField: vol.sourceField,
259+
sourceField: vol.source,
278260
},
279261
VolumeCapability: volCap,
280262
VolumeId: vol.id,
@@ -285,17 +267,38 @@ func (d *Driver) internalMount(ctx context.Context, vol *smbVolume, volCap *csi.
285267

286268
// Unmount smb server at base-dir
287269
func (d *Driver) internalUnmount(ctx context.Context, vol *smbVolume) error {
288-
targetPath := d.getInternalMountPath(vol)
270+
targetPath := getInternalMountPath(d.workingMountDir, vol)
289271

290272
// Unmount smb server at base-dir
291273
klog.V(4).Infof("internally unmounting %v", targetPath)
292274
_, err := d.NodeUnstageVolume(ctx, &csi.NodeUnstageVolumeRequest{
293275
VolumeId: vol.id,
294-
StagingTargetPath: d.getInternalMountPath(vol),
276+
StagingTargetPath: targetPath,
295277
})
296278
return err
297279
}
298280

281+
// Given a smbVolume, return a CSI volume id
282+
func getVolumeIDFromSmbVol(vol *smbVolume) string {
283+
idElements := make([]string, totalIDElements)
284+
idElements[idSource] = strings.Trim(vol.source, "/")
285+
idElements[idSubDir] = strings.Trim(vol.subDir, "/")
286+
idElements[idUUID] = vol.uuid
287+
return strings.Join(idElements, separator)
288+
}
289+
290+
// getInternalMountPath: get working directory for CreateVolume and DeleteVolume
291+
func getInternalMountPath(workingMountDir string, vol *smbVolume) string {
292+
if vol == nil {
293+
return ""
294+
}
295+
mountDir := vol.uuid
296+
if vol.uuid == "" {
297+
mountDir = vol.subDir
298+
}
299+
return filepath.Join(workingMountDir, mountDir)
300+
}
301+
299302
// Convert VolumeCreate parameters to an smbVolume
300303
func newSMBVolume(name string, size int64, params map[string]string) (*smbVolume, error) {
301304
var source, subDir string
@@ -317,8 +320,8 @@ func newSMBVolume(name string, size int64, params map[string]string) (*smbVolume
317320
}
318321

319322
vol := &smbVolume{
320-
sourceField: source,
321-
size: size,
323+
source: source,
324+
size: size,
322325
}
323326
if subDir == "" {
324327
// use pv name by default if not specified
@@ -339,8 +342,8 @@ func newSMBVolume(name string, size int64, params map[string]string) (*smbVolume
339342
// CreateVolume calls in parallel and they may use the same underlying share.
340343
// Instead of refcounting how many CreateVolume calls are using the same
341344
// share, it's simpler to just do a mount per request.
342-
func (d *Driver) getInternalVolumePath(vol *smbVolume) string {
343-
return filepath.Join(d.getInternalMountPath(vol), vol.subDir)
345+
func getInternalVolumePath(workingMountDir string, vol *smbVolume) string {
346+
return filepath.Join(getInternalMountPath(workingMountDir, vol), vol.subDir)
344347
}
345348

346349
// Convert into smbVolume into a csi.Volume
@@ -359,13 +362,16 @@ func (d *Driver) smbVolToCSI(vol *smbVolume, parameters map[string]string) *csi.
359362
func getSmbVolFromID(id string) (*smbVolume, error) {
360363
segments := strings.Split(id, separator)
361364
if len(segments) < 2 {
362-
return nil, fmt.Errorf("Could not split %q into server and subDir", id)
365+
return nil, fmt.Errorf("could not split %q into server and subDir", id)
366+
}
367+
source := segments[0]
368+
if !strings.HasPrefix(segments[0], "//") {
369+
source = "//" + source
363370
}
364-
source := "//" + segments[0]
365371
vol := &smbVolume{
366-
id: id,
367-
sourceField: source,
368-
subDir: segments[1],
372+
id: id,
373+
source: source,
374+
subDir: segments[1],
369375
}
370376
if len(segments) >= 3 {
371377
vol.uuid = segments[2]

pkg/smb/controllerserver_test.go

Lines changed: 62 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,13 @@ func TestGetSmbVolFromID(t *testing.T) {
457457
subDir: "pvc-4729891a-f57e-4982-9c60-e9884af1be2f",
458458
expectErr: false,
459459
},
460+
{
461+
desc: "correct volume id with //",
462+
volumeID: "//smb-server.default.svc.cluster.local/share#pvc-4729891a-f57e-4982-9c60-e9884af1be2f",
463+
source: "//smb-server.default.svc.cluster.local/share",
464+
subDir: "pvc-4729891a-f57e-4982-9c60-e9884af1be2f",
465+
expectErr: false,
466+
},
460467
{
461468
desc: "correct volume id with empty uuid",
462469
volumeID: "smb-server.default.svc.cluster.local/share#pvc-4729891a-f57e-4982-9c60-e9884af1be2f#",
@@ -493,7 +500,7 @@ func TestGetSmbVolFromID(t *testing.T) {
493500
smbVolume, err := getSmbVolFromID(test.volumeID)
494501

495502
if !test.expectErr {
496-
assert.Equal(t, smbVolume.sourceField, test.source)
503+
assert.Equal(t, smbVolume.source, test.source)
497504
assert.Equal(t, smbVolume.subDir, test.subDir)
498505
assert.Equal(t, smbVolume.uuid, test.uuid)
499506
assert.Nil(t, err)
@@ -513,24 +520,24 @@ func TestGetVolumeIDFromSmbVol(t *testing.T) {
513520
{
514521
desc: "volume without uuid",
515522
vol: &smbVolume{
516-
sourceField: "//smb-server.default.svc.cluster.local/share",
517-
subDir: "subdir",
523+
source: "//smb-server.default.svc.cluster.local/share",
524+
subDir: "subdir",
518525
},
519526
result: "smb-server.default.svc.cluster.local/share#subdir#",
520527
},
521528
{
522529
desc: "volume with uuid",
523530
vol: &smbVolume{
524-
sourceField: "//smb-server.default.svc.cluster.local/share",
525-
subDir: "subdir",
526-
uuid: "uuid",
531+
source: "//smb-server.default.svc.cluster.local/share",
532+
subDir: "subdir",
533+
uuid: "uuid",
527534
},
528535
result: "smb-server.default.svc.cluster.local/share#subdir#uuid",
529536
},
530537
{
531538
desc: "volume without subdir",
532539
vol: &smbVolume{
533-
sourceField: "//smb-server.default.svc.cluster.local/share",
540+
source: "//smb-server.default.svc.cluster.local/share",
534541
},
535542
result: "smb-server.default.svc.cluster.local/share##",
536543
},
@@ -542,6 +549,44 @@ func TestGetVolumeIDFromSmbVol(t *testing.T) {
542549
}
543550
}
544551

552+
func TestGetInternalMountPath(t *testing.T) {
553+
cases := []struct {
554+
desc string
555+
workingMountDir string
556+
vol *smbVolume
557+
result string
558+
}{
559+
{
560+
desc: "nil volume",
561+
workingMountDir: "/tmp",
562+
result: "",
563+
},
564+
{
565+
desc: "uuid not empty",
566+
workingMountDir: "/tmp",
567+
vol: &smbVolume{
568+
subDir: "subdir",
569+
uuid: "uuid",
570+
},
571+
result: filepath.Join("/tmp", "uuid"),
572+
},
573+
{
574+
desc: "uuid empty",
575+
workingMountDir: "/tmp",
576+
vol: &smbVolume{
577+
subDir: "subdir",
578+
uuid: "",
579+
},
580+
result: filepath.Join("/tmp", "subdir"),
581+
},
582+
}
583+
584+
for _, test := range cases {
585+
path := getInternalMountPath(test.workingMountDir, test.vol)
586+
assert.Equal(t, path, test.result)
587+
}
588+
}
589+
545590
func TestNewSMBVolume(t *testing.T) {
546591
cases := []struct {
547592
desc string
@@ -560,11 +605,11 @@ func TestNewSMBVolume(t *testing.T) {
560605
"subDir": "subdir",
561606
},
562607
expectVol: &smbVolume{
563-
id: "smb-server.default.svc.cluster.local/share#subdir#pv-name",
564-
sourceField: "//smb-server.default.svc.cluster.local/share",
565-
subDir: "subdir",
566-
size: 100,
567-
uuid: "pv-name",
608+
id: "smb-server.default.svc.cluster.local/share#subdir#pv-name",
609+
source: "//smb-server.default.svc.cluster.local/share",
610+
subDir: "subdir",
611+
size: 100,
612+
uuid: "pv-name",
568613
},
569614
},
570615
{
@@ -575,11 +620,11 @@ func TestNewSMBVolume(t *testing.T) {
575620
"source": "//smb-server.default.svc.cluster.local/share",
576621
},
577622
expectVol: &smbVolume{
578-
id: "smb-server.default.svc.cluster.local/share#pv-name#",
579-
sourceField: "//smb-server.default.svc.cluster.local/share",
580-
subDir: "pv-name",
581-
size: 200,
582-
uuid: "",
623+
id: "smb-server.default.svc.cluster.local/share#pv-name#",
624+
source: "//smb-server.default.svc.cluster.local/share",
625+
subDir: "pv-name",
626+
size: 200,
627+
uuid: "",
583628
},
584629
},
585630
{

pkg/smb/smb.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,18 @@ func hasGuestMountOptions(options []string) bool {
141141
}
142142
return false
143143
}
144+
145+
// setKeyValueInMap set key/value pair in map
146+
// key in the map is case insensitive, if key already exists, overwrite existing value
147+
func setKeyValueInMap(m map[string]string, key, value string) {
148+
if m == nil {
149+
return
150+
}
151+
for k := range m {
152+
if strings.EqualFold(k, key) {
153+
m[k] = value
154+
return
155+
}
156+
}
157+
m[key] = value
158+
}

0 commit comments

Comments
 (0)