@@ -18,6 +18,8 @@ package controller
1818
1919import (
2020 "fmt"
21+ "strings"
22+
2123 "github.com/golang/glog"
2224 crdv1 "github.com/kubernetes-csi/external-snapshotter/pkg/apis/volumesnapshot/v1alpha1"
2325 "k8s.io/api/core/v1"
@@ -37,12 +39,41 @@ var (
3739 keyFunc = cache .DeletionHandlingMetaNamespaceKeyFunc
3840)
3941
40- const snapshotterSecretNameKey = "csiSnapshotterSecretName"
41- const snapshotterSecretNamespaceKey = "csiSnapshotterSecretNamespace"
42+ type deprecatedSecretParamsMap struct {
43+ name string
44+ deprecatedSecretNameKey string
45+ deprecatedSecretNamespaceKey string
46+ secretNameKey string
47+ secretNamespaceKey string
48+ }
49+
50+ const (
51+ // CSI Parameters prefixed with csiParameterPrefix are not passed through
52+ // to the driver on CreateSnapshotRequest calls. Instead they are intended
53+ // to be used by the CSI external-snapshotter and maybe used to populate
54+ // fields in subsequent CSI calls or Kubernetes API objects.
55+ csiParameterPrefix = "csi.storage.k8s.io/"
56+
57+ prefixedSnapshotterSecretNameKey = csiParameterPrefix + "snapshotter-secret-name"
58+ prefixedSnapshotterSecretNamespaceKey = csiParameterPrefix + "snapshotter-secret-namespace"
4259
43- // Name of finalizer on VolumeSnapshotContents that are bound by VolumeSnapshots
44- const VolumeSnapshotContentFinalizer = "snapshot.storage.kubernetes.io/volumesnapshotcontent-protection"
45- const VolumeSnapshotFinalizer = "snapshot.storage.kubernetes.io/volumesnapshot-protection"
60+ // [Deprecated] CSI Parameters that are put into fields but
61+ // NOT stripped from the parameters passed to CreateSnapshot
62+ snapshotterSecretNameKey = "csiSnapshotterSecretName"
63+ snapshotterSecretNamespaceKey = "csiSnapshotterSecretNamespace"
64+
65+ // Name of finalizer on VolumeSnapshotContents that are bound by VolumeSnapshots
66+ VolumeSnapshotContentFinalizer = "snapshot.storage.kubernetes.io/volumesnapshotcontent-protection"
67+ VolumeSnapshotFinalizer = "snapshot.storage.kubernetes.io/volumesnapshot-protection"
68+ )
69+
70+ var snapshotterSecretParams = deprecatedSecretParamsMap {
71+ name : "Snapshotter" ,
72+ deprecatedSecretNameKey : snapshotterSecretNameKey ,
73+ deprecatedSecretNamespaceKey : snapshotterSecretNamespaceKey ,
74+ secretNameKey : prefixedSnapshotterSecretNameKey ,
75+ secretNamespaceKey : prefixedSnapshotterSecretNamespaceKey ,
76+ }
4677
4778func snapshotKey (vs * crdv1.VolumeSnapshot ) string {
4879 return fmt .Sprintf ("%s/%s" , vs .Namespace , vs .Name )
@@ -130,9 +161,54 @@ func IsDefaultAnnotation(obj metav1.ObjectMeta) bool {
130161 return false
131162}
132163
133- // 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.
134- // if neither the name or namespace parameter are set, a nil reference and no error is returned.
135- // no lookup of the referenced secret is performed, and the secret may or may not exist.
164+ // verifyAndGetSecretNameAndNamespaceTemplate gets the values (templates) associated
165+ // with the parameters specified in "secret" and verifies that they are specified correctly.
166+ func verifyAndGetSecretNameAndNamespaceTemplate (secret deprecatedSecretParamsMap , snapshotClassParams map [string ]string ) (nameTemplate , namespaceTemplate string , err error ) {
167+ numName := 0
168+ numNamespace := 0
169+ if t , ok := snapshotClassParams [secret .deprecatedSecretNameKey ]; ok {
170+ nameTemplate = t
171+ numName += 1
172+ glog .Warning (deprecationWarning (secret .deprecatedSecretNameKey , secret .secretNameKey , "" ))
173+ }
174+ if t , ok := snapshotClassParams [secret .deprecatedSecretNamespaceKey ]; ok {
175+ namespaceTemplate = t
176+ numNamespace += 1
177+ glog .Warning (deprecationWarning (secret .deprecatedSecretNamespaceKey , secret .secretNamespaceKey , "" ))
178+ }
179+ if t , ok := snapshotClassParams [secret .secretNameKey ]; ok {
180+ nameTemplate = t
181+ numName += 1
182+ }
183+ if t , ok := snapshotClassParams [secret .secretNamespaceKey ]; ok {
184+ namespaceTemplate = t
185+ numNamespace += 1
186+ }
187+
188+ if numName > 1 || numNamespace > 1 {
189+ // Double specified error
190+ return "" , "" , fmt .Errorf ("%s secrets specified in paramaters with both \" csi\" and \" %s\" keys" , secret .name , csiParameterPrefix )
191+ } else if numName != numNamespace {
192+ // Not both 0 or both 1
193+ return "" , "" , fmt .Errorf ("either name and namespace for %s secrets specified, Both must be specified" , secret .name )
194+ } else if numName == 1 {
195+ // Case where we've found a name and a namespace template
196+ if nameTemplate == "" || namespaceTemplate == "" {
197+ return "" , "" , fmt .Errorf ("%s secrets specified in parameters but value of either namespace or name is empty" , secret .name )
198+ }
199+ return nameTemplate , namespaceTemplate , nil
200+ } else if numName == 0 {
201+ // No secrets specified
202+ return "" , "" , nil
203+ } else {
204+ // THIS IS NOT A VALID CASE
205+ return "" , "" , fmt .Errorf ("unknown error with getting secret name and namespace templates" )
206+ }
207+ }
208+
209+ // getSecretReference returns a reference to the secret specified in the given nameTemplate
210+ // and namespaceTemplate, or an error if the templates are not specified correctly.
211+ // No lookup of the referenced secret is performed, and the secret may or may not exist.
136212//
137213// supported tokens for name resolution:
138214// - ${volumesnapshotcontent.name}
@@ -145,20 +221,17 @@ func IsDefaultAnnotation(obj metav1.ObjectMeta) bool {
145221// - ${volumesnapshot.namespace}
146222//
147223// an error is returned in the following situations:
148- // - only one of name or namespace is provided
149- // - the name or namespace parameter contains a token that cannot be resolved
224+ // - the nameTemplate or namespaceTemplate contains a token that cannot be resolved
150225// - the resolved name is not a valid secret name
151226// - the resolved namespace is not a valid namespace name
152- func GetSecretReference (snapshotClassParams map [string ]string , snapContentName string , snapshot * crdv1.VolumeSnapshot ) (* v1.SecretReference , error ) {
153- nameTemplate , hasName := snapshotClassParams [snapshotterSecretNameKey ]
154- namespaceTemplate , hasNamespace := snapshotClassParams [snapshotterSecretNamespaceKey ]
155-
156- if ! hasName && ! hasNamespace {
157- return nil , nil
227+ func getSecretReference (snapshotClassParams map [string ]string , snapContentName string , snapshot * crdv1.VolumeSnapshot ) (* v1.SecretReference , error ) {
228+ nameTemplate , namespaceTemplate , err := verifyAndGetSecretNameAndNamespaceTemplate (snapshotterSecretParams , snapshotClassParams )
229+ if err != nil {
230+ return nil , fmt .Errorf ("failed to get name and namespace template from params: %v" , err )
158231 }
159232
160- if len ( nameTemplate ) == 0 || len ( namespaceTemplate ) == 0 {
161- return nil , fmt . Errorf ( "%s and %s parameters must be specified together" , snapshotterSecretNameKey , snapshotterSecretNamespaceKey )
233+ if nameTemplate == "" && namespaceTemplate == "" {
234+ return nil , nil
162235 }
163236
164237 ref := & v1.SecretReference {}
@@ -174,15 +247,15 @@ func GetSecretReference(snapshotClassParams map[string]string, snapContentName s
174247
175248 resolvedNamespace , err := resolveTemplate (namespaceTemplate , namespaceParams )
176249 if err != nil {
177- return nil , fmt .Errorf ("error resolving %s value %q: %v" , snapshotterSecretNamespaceKey , namespaceTemplate , err )
250+ return nil , fmt .Errorf ("error resolving value %q: %v" , namespaceTemplate , err )
178251 }
179252 glog .V (4 ).Infof ("GetSecretReference namespaceTemplate %s, namespaceParams: %+v, resolved %s" , namespaceTemplate , namespaceParams , resolvedNamespace )
180253
181254 if len (validation .IsDNS1123Label (resolvedNamespace )) > 0 {
182255 if namespaceTemplate != resolvedNamespace {
183- return nil , fmt .Errorf ("%s parameter % q resolved to %q which is not a valid namespace name" , snapshotterSecretNamespaceKey , namespaceTemplate , resolvedNamespace )
256+ return nil , fmt .Errorf ("%q resolved to %q which is not a valid namespace name" , namespaceTemplate , resolvedNamespace )
184257 }
185- return nil , fmt .Errorf ("%s parameter % q is not a valid namespace name" , snapshotterSecretNamespaceKey , namespaceTemplate )
258+ return nil , fmt .Errorf ("%q is not a valid namespace name" , namespaceTemplate )
186259 }
187260 ref .Namespace = resolvedNamespace
188261
@@ -199,13 +272,13 @@ func GetSecretReference(snapshotClassParams map[string]string, snapContentName s
199272 }
200273 resolvedName , err := resolveTemplate (nameTemplate , nameParams )
201274 if err != nil {
202- return nil , fmt .Errorf ("error resolving %s value %q: %v" , snapshotterSecretNameKey , nameTemplate , err )
275+ return nil , fmt .Errorf ("error resolving value %q: %v" , nameTemplate , err )
203276 }
204277 if len (validation .IsDNS1123Subdomain (resolvedName )) > 0 {
205278 if nameTemplate != resolvedName {
206- return nil , fmt .Errorf ("%s parameter % q resolved to %q which is not a valid secret name" , snapshotterSecretNameKey , nameTemplate , resolvedName )
279+ return nil , fmt .Errorf ("%q resolved to %q which is not a valid secret name" , nameTemplate , resolvedName )
207280 }
208- return nil , fmt .Errorf ("%s parameter % q is not a valid secret name" , snapshotterSecretNameKey , nameTemplate )
281+ return nil , fmt .Errorf ("%q is not a valid secret name" , nameTemplate )
209282 }
210283 ref .Name = resolvedName
211284
@@ -229,8 +302,8 @@ func resolveTemplate(template string, params map[string]string) (string, error)
229302 return resolved , nil
230303}
231304
232- // GetCredentials retrieves credentials stored in v1.SecretReference
233- func GetCredentials (k8s kubernetes.Interface , ref * v1.SecretReference ) (map [string ]string , error ) {
305+ // getCredentials retrieves credentials stored in v1.SecretReference
306+ func getCredentials (k8s kubernetes.Interface , ref * v1.SecretReference ) (map [string ]string , error ) {
234307 if ref == nil {
235308 return nil , nil
236309 }
@@ -271,3 +344,34 @@ func isSnapshotDeletionCandidate(snapshot *crdv1.VolumeSnapshot) bool {
271344func needToAddSnapshotFinalizer (snapshot * crdv1.VolumeSnapshot ) bool {
272345 return snapshot .ObjectMeta .DeletionTimestamp == nil && ! slice .ContainsString (snapshot .ObjectMeta .Finalizers , VolumeSnapshotFinalizer , nil )
273346}
347+
348+ func deprecationWarning (deprecatedParam , newParam , removalVersion string ) string {
349+ if removalVersion == "" {
350+ removalVersion = "a future release"
351+ }
352+ newParamPhrase := ""
353+ if len (newParam ) != 0 {
354+ newParamPhrase = fmt .Sprintf (", please use \" %s\" instead" , newParam )
355+ }
356+ return fmt .Sprintf ("\" %s\" is deprecated and will be removed in %s%s" , deprecatedParam , removalVersion , newParamPhrase )
357+ }
358+
359+ func removePrefixedParameters (param map [string ]string ) (map [string ]string , error ) {
360+ newParam := map [string ]string {}
361+ for k , v := range param {
362+ if strings .HasPrefix (k , csiParameterPrefix ) {
363+ // Check if its well known
364+ switch k {
365+ case prefixedSnapshotterSecretNameKey :
366+ case prefixedSnapshotterSecretNamespaceKey :
367+ default :
368+ return map [string ]string {}, fmt .Errorf ("found unknown parameter key \" %s\" with reserved namespace %s" , k , csiParameterPrefix )
369+ }
370+ } else {
371+ // Don't strip, add this key-value to new map
372+ // Deprecated parameters prefixed with "csi" are not stripped to preserve backwards compatibility
373+ newParam [k ] = v
374+ }
375+ }
376+ return newParam , nil
377+ }
0 commit comments