-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handle Secrets in CreateSnapshot #8
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -23,7 +23,11 @@ import ( | |
"k8s.io/api/core/v1" | ||
"k8s.io/apimachinery/pkg/api/meta" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/apimachinery/pkg/util/sets" | ||
"k8s.io/apimachinery/pkg/util/validation" | ||
"k8s.io/client-go/kubernetes" | ||
"k8s.io/client-go/tools/cache" | ||
"os" | ||
"strconv" | ||
"strings" | ||
) | ||
|
@@ -121,3 +125,118 @@ func IsDefaultAnnotation(obj metav1.ObjectMeta) bool { | |
|
||
return false | ||
} | ||
|
||
// 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. | ||
// if neither the name or namespace parameter are set, a nil reference and no error is returned. | ||
// no lookup of the referenced secret is performed, and the secret may or may not exist. | ||
// | ||
// supported tokens for name resolution: | ||
// - ${volumesnapshotcontent.name} | ||
// - ${volumesnapshot.namespace} | ||
// - ${volumesnapshot.name} | ||
// - ${volumesnapshot.annotations['ANNOTATION_KEY']} (e.g. ${pvc.annotations['example.com/snapshot-create-secret-name']}) | ||
// | ||
// supported tokens for namespace resolution: | ||
// - ${volumesnapshotcontent.name} | ||
// - ${volumesnapshot.namespace} | ||
// | ||
// an error is returned in the following situations: | ||
// - only one of name or namespace is provided | ||
// - the name or namespace parameter contains a token that cannot be resolved | ||
// - the resolved name is not a valid secret name | ||
// - the resolved namespace is not a valid namespace name | ||
func GetSecretReference(nameKey, namespaceKey string, snapshotClassParams map[string]string, snapContentName string, snapshot *crdv1.VolumeSnapshot) (*v1.SecretReference, error) { | ||
nameTemplate, hasName := snapshotClassParams[nameKey] | ||
namespaceTemplate, hasNamespace := snapshotClassParams[namespaceKey] | ||
|
||
if !hasName && !hasNamespace { | ||
return nil, nil | ||
} | ||
|
||
if len(nameTemplate) == 0 || len(namespaceTemplate) == 0 { | ||
return nil, fmt.Errorf("%s and %s parameters must be specified together", nameKey, namespaceKey) | ||
} | ||
|
||
ref := &v1.SecretReference{} | ||
|
||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is { for? |
||
// Secret namespace template can make use of the VolumeSnapshotContent name or the VolumeSnapshot namespace. | ||
// Note that neither of those things are under the control of the VolumeSnapshot user. | ||
namespaceParams := map[string]string{"volumesnapshotcontent.name": snapContentName} | ||
if snapshot != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what if snapshot == nil? |
||
namespaceParams["volumesnapshot.namespace"] = snapshot.Namespace | ||
} | ||
|
||
resolvedNamespace, err := resolveTemplate(namespaceTemplate, namespaceParams) | ||
if err != nil { | ||
return nil, fmt.Errorf("error resolving %s value %q: %v", namespaceKey, namespaceTemplate, err) | ||
} | ||
if len(validation.IsDNS1123Label(resolvedNamespace)) > 0 { | ||
if namespaceTemplate != resolvedNamespace { | ||
return nil, fmt.Errorf("%s parameter %q resolved to %q which is not a valid namespace name", namespaceKey, namespaceTemplate, resolvedNamespace) | ||
} | ||
return nil, fmt.Errorf("%s parameter %q is not a valid namespace name", namespaceKey, namespaceTemplate) | ||
} | ||
ref.Namespace = resolvedNamespace | ||
} | ||
|
||
{ | ||
// Secret name template can make use of the VolumeSnapshotContent name, VolumeSnapshot name or namespace, | ||
// or a VolumeSnapshot annotation. | ||
// Note that VolumeSnapshot name and annotations are under the VolumeSnapshot user's control. | ||
nameParams := map[string]string{"volumesnapshotcontent.name": snapContentName} | ||
if snapshot != nil { | ||
nameParams["volumesnapshot.name"] = snapshot.Name | ||
nameParams["volumesnapshot.namespace"] = snapshot.Namespace | ||
for k, v := range snapshot.Annotations { | ||
nameParams["volumesnapshot.annotations['"+k+"']"] = v | ||
} | ||
} | ||
resolvedName, err := resolveTemplate(nameTemplate, nameParams) | ||
if err != nil { | ||
return nil, fmt.Errorf("error resolving %s value %q: %v", nameKey, nameTemplate, err) | ||
} | ||
if len(validation.IsDNS1123Subdomain(resolvedName)) > 0 { | ||
if nameTemplate != resolvedName { | ||
return nil, fmt.Errorf("%s parameter %q resolved to %q which is not a valid secret name", nameKey, nameTemplate, resolvedName) | ||
} | ||
return nil, fmt.Errorf("%s parameter %q is not a valid secret name", nameKey, nameTemplate) | ||
} | ||
ref.Name = resolvedName | ||
} | ||
|
||
glog.V(4).Infof("GetSecretReference validated Secret: %+v", ref) | ||
return ref, nil | ||
} | ||
|
||
func resolveTemplate(template string, params map[string]string) (string, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add comments? |
||
missingParams := sets.NewString() | ||
resolved := os.Expand(template, func(k string) string { | ||
v, ok := params[k] | ||
if !ok { | ||
missingParams.Insert(k) | ||
} | ||
return v | ||
}) | ||
if missingParams.Len() > 0 { | ||
return "", fmt.Errorf("invalid tokens: %q", missingParams.List()) | ||
} | ||
return resolved, nil | ||
} | ||
|
||
func GetCredentials(k8s kubernetes.Interface, ref *v1.SecretReference) (map[string]string, error) { | ||
if ref == nil { | ||
return nil, nil | ||
} | ||
|
||
secret, err := k8s.CoreV1().Secrets(ref.Namespace).Get(ref.Name, metav1.GetOptions{}) | ||
if err != nil { | ||
return nil, fmt.Errorf("error getting secret %s in namespace %s: %v", ref.Name, ref.Namespace, err) | ||
} | ||
|
||
credentials := map[string]string{} | ||
for key, value := range secret.Data { | ||
credentials[key] = string(value) | ||
} | ||
return credentials, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just use !hasName || !hasNamespace to return ?