@@ -21,7 +21,6 @@ import (
2121 "fmt"
2222 "os"
2323 "path/filepath"
24- "regexp"
2524 "strings"
2625
2726 "github.com/container-storage-interface/spec/lib/go/csi"
@@ -31,8 +30,7 @@ import (
3130)
3231
3332const (
34- volumeIDRegex = "^(.*)#(.*)$"
35- sourceAndSubDirSeperator = "#"
33+ separator = "#"
3634)
3735
3836// smbVolume is an internal representation of a volume
@@ -46,17 +44,19 @@ type smbVolume struct {
4644 subDir string
4745 // size of volume
4846 size int64
47+ // pv name when subDir is not empty
48+ uuid string
4949}
5050
5151// Ordering of elements in the CSI volume id.
5252// ID is of the form {server}/{subDir}.
5353const (
5454 idsourceField = iota
5555 idSubDir
56+ idUUID
5657 totalIDElements // Always last
5758)
5859
59- // CreateVolume only supports static provisioning, no create volume action
6060func (d * Driver ) CreateVolume (ctx context.Context , req * csi.CreateVolumeRequest ) (* csi.CreateVolumeResponse , error ) {
6161 name := req .GetName ()
6262 if len (name ) == 0 {
@@ -74,41 +74,38 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
7474
7575 reqCapacity := req .GetCapacityRange ().GetRequiredBytes ()
7676 parameters := req .GetParameters ()
77- // Validate parameters (case-insensitive).
78- for k := range parameters {
79- switch strings .ToLower (k ) {
80- case paramSource :
81- // no op
82- default :
83- return nil , fmt .Errorf ("invalid parameter %s in storage class" , k )
84- }
77+ if parameters == nil {
78+ parameters = make (map [string ]string )
8579 }
86-
87- smbVol , err := d .newSMBVolume (name , reqCapacity , parameters )
80+ smbVol , err := newSMBVolume (name , reqCapacity , parameters )
8881 if err != nil {
8982 return nil , status .Error (codes .InvalidArgument , err .Error ())
9083 }
9184
9285 secrets := req .GetSecrets ()
9386 if len (secrets ) > 0 {
94- // Mount smb base share so we can create a subdirectory
95- if err := d .internalMount (ctx , smbVol , volCap , secrets ); err != nil {
96- return nil , status .Errorf (codes .Internal , "failed to mount smb server: %v" , err .Error ())
97- }
98- defer func () {
99- if err = d .internalUnmount (ctx , smbVol ); err != nil {
100- klog .Warningf ("failed to unmount smb server: %v" , err .Error ())
87+ if len (smbVol .uuid ) > 0 {
88+ klog .V (2 ).Infof ("existing subDir(%s) is provided, skip subdirectory creation" , smbVol .subDir )
89+ } else {
90+ // Mount smb base share so we can create a subdirectory
91+ if err := d .internalMount (ctx , smbVol , volCap , secrets ); err != nil {
92+ return nil , status .Errorf (codes .Internal , "failed to mount smb server: %v" , err .Error ())
10193 }
102- }()
103- // Create subdirectory under base-dir
104- // TODO: revisit permissions
105- internalVolumePath := d .getInternalVolumePath (smbVol )
106- if err = os .Mkdir (internalVolumePath , 0777 ); err != nil && ! os .IsExist (err ) {
107- return nil , status .Errorf (codes .Internal , "failed to make subdirectory: %v" , err .Error ())
94+ defer func () {
95+ if err = d .internalUnmount (ctx , smbVol ); err != nil {
96+ klog .Warningf ("failed to unmount smb server: %v" , err .Error ())
97+ }
98+ }()
99+ // Create subdirectory under base-dir
100+ // TODO: revisit permissions
101+ internalVolumePath := d .getInternalVolumePath (smbVol )
102+ if err = os .Mkdir (internalVolumePath , 0777 ); err != nil && ! os .IsExist (err ) {
103+ return nil , status .Errorf (codes .Internal , "failed to make subdirectory: %v" , err .Error ())
104+ }
105+ parameters [subDirField ] = smbVol .subDir
108106 }
109- parameters [sourceField ] = parameters [sourceField ] + "/" + smbVol .subDir
110107 } else {
111- klog .Infof ("CreateVolume(%s) does not provide secrets" , name )
108+ klog .V ( 2 ). Infof ("CreateVolume(%s) does not provide secrets" , name )
112109 }
113110 return & csi.CreateVolumeResponse {Volume : d .smbVolToCSI (smbVol , parameters )}, nil
114111}
@@ -128,21 +125,25 @@ func (d *Driver) DeleteVolume(ctx context.Context, req *csi.DeleteVolumeRequest)
128125
129126 secrets := req .GetSecrets ()
130127 if len (secrets ) > 0 {
131- // Mount smb base share so we can delete the subdirectory
132- if err = d .internalMount (ctx , smbVol , nil , secrets ); err != nil {
133- return nil , status .Errorf (codes .Internal , "failed to mount smb server: %v" , err .Error ())
134- }
135- defer func () {
136- if err = d .internalUnmount (ctx , smbVol ); err != nil {
137- klog .Warningf ("failed to unmount smb server: %v" , err .Error ())
128+ if len (smbVol .uuid ) > 0 {
129+ klog .V (2 ).Infof ("existing subDir(%s) is provided, skip subdirectory creation" , smbVol .subDir )
130+ } else {
131+ // Mount smb base share so we can delete the subdirectory
132+ if err = d .internalMount (ctx , smbVol , nil , secrets ); err != nil {
133+ return nil , status .Errorf (codes .Internal , "failed to mount smb server: %v" , err .Error ())
134+ }
135+ defer func () {
136+ if err = d .internalUnmount (ctx , smbVol ); err != nil {
137+ klog .Warningf ("failed to unmount smb server: %v" , err .Error ())
138+ }
139+ }()
140+
141+ // Delete subdirectory under base-dir
142+ internalVolumePath := d .getInternalVolumePath (smbVol )
143+ klog .V (2 ).Infof ("Removing subdirectory at %v" , internalVolumePath )
144+ if err = os .RemoveAll (internalVolumePath ); err != nil {
145+ return nil , status .Errorf (codes .Internal , "failed to delete subdirectory: %v" , err .Error ())
138146 }
139- }()
140-
141- // Delete subdirectory under base-dir
142- internalVolumePath := d .getInternalVolumePath (smbVol )
143- klog .V (2 ).Infof ("Removing subdirectory at %v" , internalVolumePath )
144- if err = os .RemoveAll (internalVolumePath ); err != nil {
145- return nil , status .Errorf (codes .Internal , "failed to delete subdirectory: %v" , err .Error ())
146147 }
147148 } else {
148149 klog .Infof ("DeleteVolume(%s) does not provide secrets" , volumeID )
@@ -211,11 +212,12 @@ func (d *Driver) ListSnapshots(ctx context.Context, req *csi.ListSnapshotsReques
211212}
212213
213214// Given a smbVolume, return a CSI volume id
214- func ( d * Driver ) getVolumeIDFromSmbVol (vol * smbVolume ) string {
215+ func getVolumeIDFromSmbVol (vol * smbVolume ) string {
215216 idElements := make ([]string , totalIDElements )
216217 idElements [idsourceField ] = strings .Trim (vol .sourceField , "/" )
217218 idElements [idSubDir ] = strings .Trim (vol .subDir , "/" )
218- return strings .Join (idElements , sourceAndSubDirSeperator )
219+ idElements [idUUID ] = vol .uuid
220+ return strings .Join (idElements , separator )
219221}
220222
221223// Get working directory for CreateVolume and DeleteVolume
@@ -266,29 +268,38 @@ func (d *Driver) internalUnmount(ctx context.Context, vol *smbVolume) error {
266268}
267269
268270// Convert VolumeCreate parameters to an smbVolume
269- func ( d * Driver ) newSMBVolume (name string , size int64 , params map [string ]string ) (* smbVolume , error ) {
270- var sourceField string
271+ func newSMBVolume (name string , size int64 , params map [string ]string ) (* smbVolume , error ) {
272+ var source , subDir string
271273
272- // Validate parameters (case-insensitive).
274+ // validate parameters (case-insensitive).
273275 for k , v := range params {
274276 switch strings .ToLower (k ) {
275- case paramSource :
276- sourceField = v
277+ case sourceField :
278+ source = v
279+ case subDirField :
280+ subDir = v
281+ default :
282+ return nil , fmt .Errorf ("invalid parameter %s in storage class" , k )
277283 }
278284 }
279285
280- // Validate required parameters
281- if sourceField == "" {
282- return nil , fmt .Errorf ("%v is a required parameter" , paramSource )
286+ if source == "" {
287+ return nil , fmt .Errorf ("%v is a required parameter" , sourceField )
283288 }
284289
285290 vol := & smbVolume {
286- sourceField : sourceField ,
287- subDir : name ,
291+ sourceField : source ,
288292 size : size ,
289293 }
290- vol .id = d .getVolumeIDFromSmbVol (vol )
291-
294+ if subDir == "" {
295+ // use pv name by default if not specified
296+ vol .subDir = name
297+ } else {
298+ vol .subDir = subDir
299+ // make volume id unique if subDir is provided
300+ vol .uuid = name
301+ }
302+ vol .id = getVolumeIDFromSmbVol (vol )
292303 return vol , nil
293304}
294305
@@ -313,17 +324,22 @@ func (d *Driver) smbVolToCSI(vol *smbVolume, parameters map[string]string) *csi.
313324}
314325
315326// Given a CSI volume id, return a smbVolume
316- // a sample volume Id: smb-server.default.svc.cluster.local/share/pvc-4729891a-f57e-4982-9c60-e9884af1be2f
327+ // sample volume Id:
328+ // smb-server.default.svc.cluster.local/share#pvc-4729891a-f57e-4982-9c60-e9884af1be2f
329+ // smb-server.default.svc.cluster.local/share#subdir#pvc-4729891a-f57e-4982-9c60-e9884af1be2f
317330func getSmbVolFromID (id string ) (* smbVolume , error ) {
318- volRegex := regexp .MustCompile (volumeIDRegex )
319- tokens := volRegex .FindStringSubmatch (id )
320- if tokens == nil || len (tokens ) != 3 {
331+ segments := strings .Split (id , separator )
332+ if len (segments ) < 2 {
321333 return nil , fmt .Errorf ("Could not split %q into server and subDir" , id )
322334 }
323- source := "//" + tokens [ 1 ]
324- return & smbVolume {
335+ source := "//" + segments [ 0 ]
336+ vol := & smbVolume {
325337 id : id ,
326338 sourceField : source ,
327- subDir : tokens [2 ],
328- }, nil
339+ subDir : segments [1 ],
340+ }
341+ if len (segments ) >= 3 {
342+ vol .uuid = segments [2 ]
343+ }
344+ return vol , nil
329345}
0 commit comments