Skip to content

Commit 9a258a0

Browse files
authored
Merge pull request #182 from davidz627/cherrypick/params
[Cherry-Pick] Add new reserved prefixed parameter keys which are stripped out of parameter list, add deprecation notice for old keys and keep their behavior the same
2 parents 3a65c77 + 2ef26b0 commit 9a258a0

File tree

2 files changed

+543
-209
lines changed

2 files changed

+543
-209
lines changed

pkg/controller/controller.go

Lines changed: 183 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
6068
const (
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
87151
type 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+
594698
func (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

Comments
 (0)