@@ -57,7 +57,37 @@ import (
5757 utilfeature "k8s.io/apiserver/pkg/util/feature"
5858)
5959
60+ type deprecatedSecretParamsMap struct {
61+ name string
62+ deprecatedSecretNameKey string
63+ deprecatedSecretNamespaceKey string
64+ secretNameKey string
65+ secretNamespaceKey string
66+ }
67+
6068const (
69+ // CSI Parameters prefixed with csiParameterPrefix are not passed through
70+ // to the driver on CreateVolumeRequest calls. Instead they are intended
71+ // to used by the CSI external-provisioner and maybe used to populate
72+ // fields in subsequent CSI calls or Kubernetes API objects.
73+ csiParameterPrefix = "csi.storage.k8s.io/"
74+
75+ prefixedFsTypeKey = csiParameterPrefix + "fstype"
76+
77+ prefixedProvisionerSecretNameKey = csiParameterPrefix + "provisioner-secret-name"
78+ prefixedProvisionerSecretNamespaceKey = csiParameterPrefix + "provisioner-secret-namespace"
79+
80+ prefixedControllerPublishSecretNameKey = csiParameterPrefix + "controller-publish-secret-name"
81+ prefixedControllerPublishSecretNamespaceKey = csiParameterPrefix + "controller-publish-secret-namespace"
82+
83+ prefixedNodeStageSecretNameKey = csiParameterPrefix + "node-stage-secret-name"
84+ prefixedNodeStageSecretNamespaceKey = csiParameterPrefix + "node-stage-secret-namespace"
85+
86+ prefixedNodePublishSecretNameKey = csiParameterPrefix + "node-publish-secret-name"
87+ prefixedNodePublishSecretNamespaceKey = csiParameterPrefix + "node-publish-secret-namespace"
88+
89+ // [Deprecated] CSI Parameters that are put into fields but
90+ // NOT stripped from the parameters passed to CreateVolume
6191 provisionerSecretNameKey = "csiProvisionerSecretName"
6292 provisionerSecretNamespaceKey = "csiProvisionerSecretNamespace"
6393
@@ -83,6 +113,40 @@ const (
83113 snapshotAPIGroup = snapapi .GroupName // "snapshot.storage.k8s.io"
84114)
85115
116+ var (
117+ provisionerSecretParams = deprecatedSecretParamsMap {
118+ name : "Provisioner" ,
119+ deprecatedSecretNameKey : provisionerSecretNameKey ,
120+ deprecatedSecretNamespaceKey : provisionerSecretNamespaceKey ,
121+ secretNameKey : prefixedProvisionerSecretNameKey ,
122+ secretNamespaceKey : prefixedProvisionerSecretNamespaceKey ,
123+ }
124+
125+ nodePublishSecretParams = deprecatedSecretParamsMap {
126+ name : "NodePublish" ,
127+ deprecatedSecretNameKey : nodePublishSecretNameKey ,
128+ deprecatedSecretNamespaceKey : nodePublishSecretNamespaceKey ,
129+ secretNameKey : prefixedNodePublishSecretNameKey ,
130+ secretNamespaceKey : prefixedNodePublishSecretNamespaceKey ,
131+ }
132+
133+ controllerPublishSecretParams = deprecatedSecretParamsMap {
134+ name : "ControllerPublish" ,
135+ deprecatedSecretNameKey : controllerPublishSecretNameKey ,
136+ deprecatedSecretNamespaceKey : controllerPublishSecretNamespaceKey ,
137+ secretNameKey : prefixedControllerPublishSecretNameKey ,
138+ secretNamespaceKey : prefixedControllerPublishSecretNamespaceKey ,
139+ }
140+
141+ nodeStageSecretParams = deprecatedSecretParamsMap {
142+ name : "NodeStage" ,
143+ deprecatedSecretNameKey : nodeStageSecretNameKey ,
144+ deprecatedSecretNamespaceKey : nodeStageSecretNamespaceKey ,
145+ secretNameKey : prefixedNodeStageSecretNameKey ,
146+ secretNamespaceKey : prefixedNodeStageSecretNamespaceKey ,
147+ }
148+ )
149+
86150// CSIProvisioner struct
87151type csiProvisioner struct {
88152 client kubernetes.Interface
@@ -416,13 +480,21 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
416480 return nil , err
417481 }
418482
483+ fsTypesFound := 0
419484 fsType := ""
420485 for k , v := range options .Parameters {
421- switch strings .ToLower (k ) {
422- case "fstype" :
486+ if strings .ToLower (k ) == "fstype" {
487+ fsType = v
488+ fsTypesFound += 1
489+ glog .Warningf (deprecationWarning ("fstype" , prefixedFsTypeKey , "" ))
490+ } else if k == prefixedFsTypeKey {
423491 fsType = v
492+ fsTypesFound += 1
424493 }
425494 }
495+ if fsTypesFound > 1 {
496+ return nil , fmt .Errorf ("fstype specified in parameters with both \" fstype\" and \" %s\" keys" , prefixedFsTypeKey )
497+ }
426498 if len (fsType ) == 0 {
427499 fsType = defaultFSType
428500 }
@@ -475,7 +547,7 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
475547
476548 // Resolve provision secret credentials.
477549 // No PVC is provided when resolving provision/delete secret names, since the PVC may or may not exist at delete time.
478- provisionerSecretRef , err := getSecretReference (provisionerSecretNameKey , provisionerSecretNamespaceKey , options .Parameters , pvName , nil )
550+ provisionerSecretRef , err := getSecretReference (provisionerSecretParams , options .Parameters , pvName , nil )
479551 if err != nil {
480552 return nil , err
481553 }
@@ -486,19 +558,24 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
486558 req .Secrets = provisionerCredentials
487559
488560 // Resolve controller publish, node stage, node publish secret references
489- controllerPublishSecretRef , err := getSecretReference (controllerPublishSecretNameKey , controllerPublishSecretNamespaceKey , options .Parameters , pvName , options .PVC )
561+ controllerPublishSecretRef , err := getSecretReference (controllerPublishSecretParams , options .Parameters , pvName , options .PVC )
490562 if err != nil {
491563 return nil , err
492564 }
493- nodeStageSecretRef , err := getSecretReference (nodeStageSecretNameKey , nodeStageSecretNamespaceKey , options .Parameters , pvName , options .PVC )
565+ nodeStageSecretRef , err := getSecretReference (nodeStageSecretParams , options .Parameters , pvName , options .PVC )
494566 if err != nil {
495567 return nil , err
496568 }
497- nodePublishSecretRef , err := getSecretReference (nodePublishSecretNameKey , nodePublishSecretNamespaceKey , options .Parameters , pvName , options .PVC )
569+ nodePublishSecretRef , err := getSecretReference (nodePublishSecretParams , options .Parameters , pvName , options .PVC )
498570 if err != nil {
499571 return nil , err
500572 }
501573
574+ req .Parameters , err = removePrefixedParameters (options .Parameters )
575+ if err != nil {
576+ return nil , fmt .Errorf ("failed to strip CSI Parameters of prefixed keys: %v" , err )
577+ }
578+
502579 opts := wait.Backoff {Duration : backoffDuration , Factor : backoffFactor , Steps : backoffSteps }
503580 err = wait .ExponentialBackoff (opts , func () (bool , error ) {
504581 ctx , cancel := context .WithTimeout (context .Background (), p .timeout )
@@ -591,6 +668,33 @@ func (p *csiProvisioner) Provision(options controller.VolumeOptions) (*v1.Persis
591668 return pv , nil
592669}
593670
671+ func removePrefixedParameters (param map [string ]string ) (map [string ]string , error ) {
672+ newParam := map [string ]string {}
673+ for k , v := range param {
674+ if strings .HasPrefix (k , csiParameterPrefix ) {
675+ // Check if its well known
676+ switch k {
677+ case prefixedFsTypeKey :
678+ case prefixedProvisionerSecretNameKey :
679+ case prefixedProvisionerSecretNamespaceKey :
680+ case prefixedControllerPublishSecretNameKey :
681+ case prefixedControllerPublishSecretNamespaceKey :
682+ case prefixedNodeStageSecretNameKey :
683+ case prefixedNodeStageSecretNamespaceKey :
684+ case prefixedNodePublishSecretNameKey :
685+ case prefixedNodePublishSecretNamespaceKey :
686+ default :
687+ return map [string ]string {}, fmt .Errorf ("found unknown parameter key \" %s\" with reserved namespace %s" , k , csiParameterPrefix )
688+ }
689+ } else {
690+ // Don't strip, add this key-value to new map
691+ // Deprecated parameters prefixed with "csi" are not stripped to preserve backwards compatibility
692+ newParam [k ] = v
693+ }
694+ }
695+ return newParam , nil
696+ }
697+
594698func (p * csiProvisioner ) getVolumeContentSource (options controller.VolumeOptions ) (* csi.VolumeContentSource , error ) {
595699 snapshotObj , err := p .snapshotClient .VolumesnapshotV1alpha1 ().VolumeSnapshots (options .PVC .Namespace ).Get (options .PVC .Spec .DataSource .Name , metav1.GetOptions {})
596700 if err != nil {
@@ -666,7 +770,7 @@ func (p *csiProvisioner) Delete(volume *v1.PersistentVolume) error {
666770 if storageClass , err := p .client .StorageV1 ().StorageClasses ().Get (storageClassName , metav1.GetOptions {}); err == nil {
667771 // Resolve provision secret credentials.
668772 // No PVC is provided when resolving provision/delete secret names, since the PVC may or may not exist at delete time.
669- provisionerSecretRef , err := getSecretReference (provisionerSecretNameKey , provisionerSecretNamespaceKey , storageClass .Parameters , volume .Name , nil )
773+ provisionerSecretRef , err := getSecretReference (provisionerSecretParams , storageClass .Parameters , volume .Name , nil )
670774 if err != nil {
671775 return err
672776 }
@@ -703,8 +807,54 @@ func (p *csiProvisioner) volumeHandleToId(handle string) string {
703807 return handle
704808}
705809
706- // getSecretReference returns a reference to the secret specified in the given nameKey and namespaceKey parameters, or an error if the parameters are not specified correctly.
707- // if neither the name or namespace parameter are set, a nil reference and no error is returned.
810+ // verifyAndGetSecretNameAndNamespaceTemplate gets the values (templates) associated
811+ // with the parameters specified in "secret" and verifies that they are specified correctly.
812+ func verifyAndGetSecretNameAndNamespaceTemplate (secret deprecatedSecretParamsMap , storageClassParams map [string ]string ) (nameTemplate , namespaceTemplate string , err error ) {
813+ numName := 0
814+ numNamespace := 0
815+
816+ if t , ok := storageClassParams [secret .deprecatedSecretNameKey ]; ok {
817+ nameTemplate = t
818+ numName += 1
819+ glog .Warning (deprecationWarning (secret .deprecatedSecretNameKey , secret .secretNameKey , "" ))
820+ }
821+ if t , ok := storageClassParams [secret .deprecatedSecretNamespaceKey ]; ok {
822+ namespaceTemplate = t
823+ numNamespace += 1
824+ glog .Warning (deprecationWarning (secret .deprecatedSecretNamespaceKey , secret .secretNamespaceKey , "" ))
825+ }
826+ if t , ok := storageClassParams [secret .secretNameKey ]; ok {
827+ nameTemplate = t
828+ numName += 1
829+ }
830+ if t , ok := storageClassParams [secret .secretNamespaceKey ]; ok {
831+ namespaceTemplate = t
832+ numNamespace += 1
833+ }
834+
835+ if numName > 1 || numNamespace > 1 {
836+ // Double specified error
837+ return "" , "" , fmt .Errorf ("%s secrets specified in parameters with both \" csi\" and \" %s\" keys" , secret .name , csiParameterPrefix )
838+ } else if numName != numNamespace {
839+ // Not both 0 or both 1
840+ return "" , "" , fmt .Errorf ("either name and namespace for %s secrets specified, Both must be specified" , secret .name )
841+ } else if numName == 1 {
842+ // Case where we've found a name and a namespace template
843+ if nameTemplate == "" || namespaceTemplate == "" {
844+ return "" , "" , fmt .Errorf ("%s secrets specified in parameters but value of either namespace or name is empty" , secret .name )
845+ }
846+ return nameTemplate , namespaceTemplate , nil
847+ } else if numName == 0 {
848+ // No secrets specified
849+ return "" , "" , nil
850+ } else {
851+ // THIS IS NOT A VALID CASE
852+ return "" , "" , fmt .Errorf ("unknown error with getting secret name and namespace templates" )
853+ }
854+ }
855+
856+ // getSecretReference returns a reference to the secret specified in the given nameTemplate
857+ // and namespaceTemplate, or an error if the templates are not specified correctly.
708858// no lookup of the referenced secret is performed, and the secret may or may not exist.
709859//
710860// supported tokens for name resolution:
@@ -718,24 +868,19 @@ func (p *csiProvisioner) volumeHandleToId(handle string) string {
718868// - ${pvc.namespace}
719869//
720870// an error is returned in the following situations:
721- // - only one of name or namespace is provided
722- // - the name or namespace parameter contains a token that cannot be resolved
871+ // - the nameTemplate or namespaceTemplate contains a token that cannot be resolved
723872// - the resolved name is not a valid secret name
724873// - the resolved namespace is not a valid namespace name
725- func getSecretReference (nameKey , namespaceKey string , storageClassParams map [string ]string , pvName string , pvc * v1.PersistentVolumeClaim ) (* v1.SecretReference , error ) {
726- nameTemplate , hasName := storageClassParams [nameKey ]
727- namespaceTemplate , hasNamespace := storageClassParams [namespaceKey ]
728-
729- if ! hasName && ! hasNamespace {
730- return nil , nil
874+ func getSecretReference (secretParams deprecatedSecretParamsMap , storageClassParams map [string ]string , pvName string , pvc * v1.PersistentVolumeClaim ) (* v1.SecretReference , error ) {
875+ nameTemplate , namespaceTemplate , err := verifyAndGetSecretNameAndNamespaceTemplate (secretParams , storageClassParams )
876+ if err != nil {
877+ return nil , fmt .Errorf ("failed to get name and namespace template from params: %v" , err )
731878 }
732-
733- if len (nameTemplate ) == 0 || len (namespaceTemplate ) == 0 {
734- return nil , fmt .Errorf ("%s and %s parameters must be specified together" , nameKey , namespaceKey )
879+ if nameTemplate == "" && namespaceTemplate == "" {
880+ return nil , nil
735881 }
736882
737883 ref := & v1.SecretReference {}
738-
739884 {
740885 // Secret namespace template can make use of the PV name or the PVC namespace.
741886 // Note that neither of those things are under the control of the PVC user.
@@ -746,13 +891,13 @@ func getSecretReference(nameKey, namespaceKey string, storageClassParams map[str
746891
747892 resolvedNamespace , err := resolveTemplate (namespaceTemplate , namespaceParams )
748893 if err != nil {
749- return nil , fmt .Errorf ("error resolving %s value %q: %v" , namespaceKey , namespaceTemplate , err )
894+ return nil , fmt .Errorf ("error resolving value %q: %v" , namespaceTemplate , err )
750895 }
751896 if len (validation .IsDNS1123Label (resolvedNamespace )) > 0 {
752897 if namespaceTemplate != resolvedNamespace {
753- return nil , fmt .Errorf ("%s parameter % q resolved to %q which is not a valid namespace name" , namespaceKey , namespaceTemplate , resolvedNamespace )
898+ return nil , fmt .Errorf ("%q resolved to %q which is not a valid namespace name" , namespaceTemplate , resolvedNamespace )
754899 }
755- return nil , fmt .Errorf ("%s parameter % q is not a valid namespace name" , namespaceKey , namespaceTemplate )
900+ return nil , fmt .Errorf ("%q is not a valid namespace name" , namespaceTemplate )
756901 }
757902 ref .Namespace = resolvedNamespace
758903 }
@@ -770,13 +915,13 @@ func getSecretReference(nameKey, namespaceKey string, storageClassParams map[str
770915 }
771916 resolvedName , err := resolveTemplate (nameTemplate , nameParams )
772917 if err != nil {
773- return nil , fmt .Errorf ("error resolving %s value %q: %v" , nameKey , nameTemplate , err )
918+ return nil , fmt .Errorf ("error resolving value %q: %v" , nameTemplate , err )
774919 }
775920 if len (validation .IsDNS1123Subdomain (resolvedName )) > 0 {
776921 if nameTemplate != resolvedName {
777- return nil , fmt .Errorf ("%s parameter % q resolved to %q which is not a valid secret name" , nameKey , nameTemplate , resolvedName )
922+ return nil , fmt .Errorf ("%q resolved to %q which is not a valid secret name" , nameTemplate , resolvedName )
778923 }
779- return nil , fmt .Errorf ("%s parameter % q is not a valid secret name" , nameKey , nameTemplate )
924+ return nil , fmt .Errorf ("%q is not a valid secret name" , nameTemplate )
780925 }
781926 ref .Name = resolvedName
782927 }
@@ -835,3 +980,14 @@ func bytesToGiQuantity(bytes int64) resource.Quantity {
835980 stringQuantity := fmt .Sprintf ("%v%s" , num , suffix )
836981 return resource .MustParse (stringQuantity )
837982}
983+
984+ func deprecationWarning (deprecatedParam , newParam , removalVersion string ) string {
985+ if removalVersion == "" {
986+ removalVersion = "a future release"
987+ }
988+ newParamPhrase := ""
989+ if len (newParam ) != 0 {
990+ newParamPhrase = fmt .Sprintf (", please use \" %s\" instead" , newParam )
991+ }
992+ return fmt .Sprintf ("\" %s\" is deprecated and will be removed in %s%s" , deprecatedParam , removalVersion , newParamPhrase )
993+ }
0 commit comments