@@ -44,10 +44,11 @@ const (
4444 secretNamespaceKey = "csiProvisionerSecretNamespace"
4545)
4646
47+ // CSIProvisioner struct
4748type csiProvisioner struct {
4849 client kubernetes.Interface
4950 csiClient csi.ControllerClient
50- driverName string
51+ grpcClient * grpc. ClientConn
5152 timeout time.Duration
5253 identity string
5354 volumeNamePrefix string
@@ -80,7 +81,7 @@ func logGRPC(ctx context.Context, method string, req, reply interface{}, cc *grp
8081 return err
8182}
8283
83- func connect (address string , timeout time.Duration ) (* grpc.ClientConn , error ) {
84+ func Connect (address string , timeout time.Duration ) (* grpc.ClientConn , error ) {
8485 glog .V (2 ).Infof ("Connecting to %s" , address )
8586 dialOptions := []grpc.DialOption {
8687 grpc .WithInsecure (),
@@ -102,7 +103,7 @@ func connect(address string, timeout time.Duration) (*grpc.ClientConn, error) {
102103 for {
103104 if ! conn .WaitForStateChange (ctx , conn .GetState ()) {
104105 glog .V (4 ).Infof ("Connection timed out" )
105- return conn , nil // return nil, subsequent GetPluginInfo will show the real connection error
106+ return conn , fmt . Errorf ( "Connection timed out" )
106107 }
107108 if conn .GetState () == connectivity .Ready {
108109 glog .V (3 ).Infof ("Connected" )
@@ -185,34 +186,19 @@ func supportsControllerCreateVolume(conn *grpc.ClientConn, timeout time.Duration
185186 return false , nil
186187}
187188
188- func NewCSIProvisioner (client kubernetes.Interface , csiEndpoint string , connectionTimeout time.Duration , identity string , volumeNamePrefix string , volumeNameUUIDLength int ) controller.Provisioner {
189- grpcClient , err := connect (csiEndpoint , connectionTimeout )
190- if err != nil || grpcClient == nil {
191- glog .Fatalf ("failed to connect to csi endpoint :%v" , err )
192- }
193- ok , err := supportsPluginControllerService (grpcClient , connectionTimeout )
194- if err != nil {
195- glog .Fatalf ("failed to get support info :%v" , err )
196- }
197- if ! ok {
198- glog .Fatalf ("no plugin controller service support detected" )
199- }
200- ok , err = supportsControllerCreateVolume (grpcClient , connectionTimeout )
201- if err != nil {
202- glog .Fatalf ("failed to get support info :%v" , err )
203- }
204- if ! ok {
205- glog .Fatalf ("no create/delete volume support detected" )
206- }
207- driver , err := getDriverName (grpcClient , connectionTimeout )
208- if err != nil {
209- glog .Fatalf ("failed to get driver info :%v" , err )
210- }
189+ // NewCSIProvisioner creates new CSI provisioner
190+ func NewCSIProvisioner (client kubernetes.Interface ,
191+ csiEndpoint string ,
192+ connectionTimeout time.Duration ,
193+ identity string ,
194+ volumeNamePrefix string ,
195+ volumeNameUUIDLength int ,
196+ grpcClient * grpc.ClientConn ) controller.Provisioner {
211197
212198 csiClient := csi .NewControllerClient (grpcClient )
213199 provisioner := & csiProvisioner {
214200 client : client ,
215- driverName : driver ,
201+ grpcClient : grpcClient ,
216202 csiClient : csiClient ,
217203 timeout : connectionTimeout ,
218204 identity : identity ,
@@ -222,10 +208,45 @@ func NewCSIProvisioner(client kubernetes.Interface, csiEndpoint string, connecti
222208 return provisioner
223209}
224210
211+ // This function get called before any attepmt to communicate with the driver.
212+ // Before initiating Create/Delete API calls provisioner checks if Capabilities:
213+ // PluginControllerService, ControllerCreateVolume sre supported and gets the driver name.
214+ func checkDriverState (grpcClient * grpc.ClientConn , timeout time.Duration ) (string , error ) {
215+ ok , err := supportsPluginControllerService (grpcClient , timeout )
216+ if err != nil {
217+ glog .Errorf ("failed to get support info :%v" , err )
218+ return "" , err
219+ }
220+ if ! ok {
221+ glog .Errorf ("no plugin controller service support detected" )
222+ return "" , fmt .Errorf ("no plugin controller service support detected" )
223+ }
224+ ok , err = supportsControllerCreateVolume (grpcClient , timeout )
225+ if err != nil {
226+ glog .Errorf ("failed to get support info :%v" , err )
227+ return "" , err
228+ }
229+ if ! ok {
230+ glog .Error ("no create/delete volume support detected" )
231+ return "" , fmt .Errorf ("no create/delete volume support detected" )
232+ }
233+ driverName , err := getDriverName (grpcClient , timeout )
234+ if err != nil {
235+ glog .Errorf ("failed to get driver info :%v" , err )
236+ return "" , err
237+ }
238+ return driverName , nil
239+ }
240+
225241func (p * csiProvisioner ) Provision (options controller.VolumeOptions ) (* v1.PersistentVolume , error ) {
226242 if options .PVC .Spec .Selector != nil {
227243 return nil , fmt .Errorf ("claim Selector is not supported" )
228244 }
245+
246+ driverName , err := checkDriverState (p .grpcClient , p .timeout )
247+ if err != nil {
248+ return nil , err
249+ }
229250 // create random share name
230251 share := fmt .Sprintf ("%s-%s" , p .volumeNamePrefix , strings .Replace (string (uuid .NewUUID ()), "-" , "" , - 1 )[0 :p .volumeNameUUIDLength ])
231252 capacity := options .PVC .Spec .Resources .Requests [v1 .ResourceName (v1 .ResourceStorage )]
@@ -249,7 +270,11 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
249270 }
250271 secret := v1.SecretReference {}
251272 if options .Parameters != nil {
252- req .ControllerCreateSecrets = getCredentialsFromParameters (p .client , options .Parameters )
273+ credentials , err := getCredentialsFromParameters (p .client , options .Parameters )
274+ if err != nil {
275+ return nil , err
276+ }
277+ req .ControllerCreateSecrets = credentials
253278 secret .Name , secret .Namespace , _ = getSecretAndNamespaceFromParameters (options .Parameters )
254279 }
255280 ctx , cancel := context .WithTimeout (context .Background (), p .timeout )
@@ -279,7 +304,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
279304 // TODO wait for CSI VolumeSource API
280305 PersistentVolumeSource : v1.PersistentVolumeSource {
281306 CSI : & v1.CSIPersistentVolumeSource {
282- Driver : p . driverName ,
307+ Driver : driverName ,
283308 VolumeHandle : p .volumeIdToHandle (rep .Volume .Id ),
284309 VolumeAttributes : volumeAttributes ,
285310 },
@@ -300,21 +325,30 @@ func (p *csiProvisioner) Delete(volume *v1.PersistentVolume) error {
300325 }
301326 volumeId := p .volumeHandleToId (volume .Spec .CSI .VolumeHandle )
302327
328+ _ , err := checkDriverState (p .grpcClient , p .timeout )
329+ if err != nil {
330+ return err
331+ }
332+
303333 req := csi.DeleteVolumeRequest {
304334 VolumeId : volumeId ,
305335 }
306336 // get secrets if StorageClass specifies it
307337 storageClassName := volume .Spec .StorageClassName
308338 if len (storageClassName ) != 0 {
309339 if storageClass , err := p .client .StorageV1 ().StorageClasses ().Get (storageClassName , metav1.GetOptions {}); err == nil {
310- req .ControllerDeleteSecrets = getCredentialsFromParameters (p .client , storageClass .Parameters )
340+ credentials , err := getCredentialsFromParameters (p .client , storageClass .Parameters )
341+ if err != nil {
342+ return err
343+ }
344+ req .ControllerDeleteSecrets = credentials
311345 }
312346
313347 }
314348 ctx , cancel := context .WithTimeout (context .Background (), p .timeout )
315349 defer cancel ()
316350
317- _ , err : = p .csiClient .DeleteVolume (ctx , & req )
351+ _ , err = p .csiClient .DeleteVolume (ctx , & req )
318352
319353 return err
320354}
@@ -330,11 +364,11 @@ func getSecretAndNamespaceFromParameters(parameters map[string]string) (string,
330364 return "" , "" , false
331365}
332366
333- func getCredentialsFromParameters (k8s kubernetes.Interface , parameters map [string ]string ) map [string ]string {
367+ func getCredentialsFromParameters (k8s kubernetes.Interface , parameters map [string ]string ) ( map [string ]string , error ) {
334368 if secretName , namespace , found := getSecretAndNamespaceFromParameters (parameters ); found {
335369 return getCredentialsFromSecret (k8s , secretName , namespace )
336370 }
337- return map [string ]string {}
371+ return map [string ]string {}, nil
338372}
339373
340374//TODO use a unique volume handle from and to Id
@@ -346,19 +380,18 @@ func (p *csiProvisioner) volumeHandleToId(handle string) string {
346380 return handle
347381}
348382
349- func getCredentialsFromSecret (k8s kubernetes.Interface , secretName , nameSpace string ) map [string ]string {
383+ func getCredentialsFromSecret (k8s kubernetes.Interface , secretName , nameSpace string ) ( map [string ]string , error ) {
350384 credentials := map [string ]string {}
351385 if len (secretName ) == 0 {
352- return credentials
386+ return credentials , nil
353387 }
354388 secret , err := k8s .CoreV1 ().Secrets (nameSpace ).Get (secretName , metav1.GetOptions {})
355389 if err != nil {
356- glog .Warningf ("failed to find the secret %s in the namespace %s with error: %v\n " , secretName , nameSpace , err )
357- return credentials
390+ return credentials , fmt .Errorf ("failed to find the secret %s in the namespace %s with error: %v\n " , secretName , nameSpace , err )
358391 }
359392 for key , value := range secret .Data {
360393 credentials [key ] = string (value )
361394 }
362395
363- return credentials
396+ return credentials , nil
364397}
0 commit comments