Skip to content

Commit

Permalink
Add snapshot secret reference to group snapshot controller.
Browse files Browse the repository at this point in the history
Fixes: kubernetes-csi#834
Signed-off-by: Manish <[email protected]>
  • Loading branch information
manishym committed Mar 21, 2024
1 parent 533a2ee commit 5e1f0b0
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 10 deletions.
28 changes: 21 additions & 7 deletions pkg/common-controller/groupsnapshot_controller_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ func (ctrl *csiSnapshotCommonController) createGroupSnapshotContent(groupSnapsho
TODO: Add PVC finalizer
*/

groupSnapshotClass, volumes, contentName, err := ctrl.getCreateGroupSnapshotInput(groupSnapshot)
groupSnapshotClass, volumes, contentName, snapshotterSecretRef, err := ctrl.getCreateGroupSnapshotInput(groupSnapshot)
if err != nil {
return nil, fmt.Errorf("failed to get input parameters to create group snapshot %s: %q", groupSnapshot.Name, err)
}
Expand Down Expand Up @@ -773,8 +773,15 @@ func (ctrl *csiSnapshotCommonController) createGroupSnapshotContent(groupSnapsho
}

/*
TODO: Add secret reference details
Add secret reference details
*/
if snapshotterSecretRef != nil {
klog.V(5).Infof("createGroupSnapshotContent: set annotation [%s] on content [%s].", utils.AnnDeletionSecretRefName, groupSnapshotContent.Name)
metav1.SetMetaDataAnnotation(&groupSnapshotContent.ObjectMeta, utils.AnnDeletionSecretRefName, snapshotterSecretRef.Name)

klog.V(5).Infof("creategroupSnapshotContent: set annotation [%s] on content [%s].", utils.AnnDeletionSecretRefNamespace, groupSnapshotContent.Name)
metav1.SetMetaDataAnnotation(&groupSnapshotContent.ObjectMeta, utils.AnnDeletionSecretRefNamespace, snapshotterSecretRef.Namespace)
}

var updateGroupSnapshotContent *crdv1alpha1.VolumeGroupSnapshotContent
klog.V(5).Infof("volume group snapshot content %#v", groupSnapshotContent)
Expand Down Expand Up @@ -810,7 +817,7 @@ func (ctrl *csiSnapshotCommonController) createGroupSnapshotContent(groupSnapsho
return updateGroupSnapshotContent, nil
}

func (ctrl *csiSnapshotCommonController) getCreateGroupSnapshotInput(groupSnapshot *crdv1alpha1.VolumeGroupSnapshot) (*crdv1alpha1.VolumeGroupSnapshotClass, []*v1.PersistentVolume, string, error) {
func (ctrl *csiSnapshotCommonController) getCreateGroupSnapshotInput(groupSnapshot *crdv1alpha1.VolumeGroupSnapshot) (*crdv1alpha1.VolumeGroupSnapshotClass, []*v1.PersistentVolume, string, *v1.SecretReference, error) {
className := groupSnapshot.Spec.VolumeGroupSnapshotClassName
klog.V(5).Infof("getCreateGroupSnapshotInput [%s]", groupSnapshot.Name)
var groupSnapshotClass *crdv1alpha1.VolumeGroupSnapshotClass
Expand All @@ -819,23 +826,30 @@ func (ctrl *csiSnapshotCommonController) getCreateGroupSnapshotInput(groupSnapsh
groupSnapshotClass, err = ctrl.getGroupSnapshotClass(*className)
if err != nil {
klog.Errorf("getCreateGroupSnapshotInput failed to getClassFromVolumeGroupSnapshot %s", err)
return nil, nil, "", err
return nil, nil, "", nil, err
}
} else {
klog.Errorf("failed to getCreateGroupSnapshotInput %s without a group snapshot class", groupSnapshot.Name)
return nil, nil, "", fmt.Errorf("failed to take group snapshot %s without a group snapshot class", groupSnapshot.Name)
return nil, nil, "", nil, fmt.Errorf("failed to take group snapshot %s without a group snapshot class", groupSnapshot.Name)
}

volumes, err := ctrl.getVolumesFromVolumeGroupSnapshot(groupSnapshot)
if err != nil {
klog.Errorf("getCreateGroupSnapshotInput failed to get PersistentVolume objects [%s]: Error: [%#v]", groupSnapshot.Name, err)
return nil, nil, "", err
return nil, nil, "", nil, err
}

// Create VolumeGroupSnapshotContent name
contentName := utils.GetDynamicSnapshotContentNameForGroupSnapshot(groupSnapshot)

return groupSnapshotClass, volumes, contentName, nil
// Get the secret reference
snapshotterSecretRef, err := utils.GetGroupSnapshotSecretReference(utils.SnapshotterSecretParams, groupSnapshotClass.Parameters, contentName, groupSnapshot)

if err != nil {
return nil, nil, "", nil, err
}

return groupSnapshotClass, volumes, contentName, snapshotterSecretRef, nil
}

// syncGroupSnapshotContent deals with one key off the queue
Expand Down
51 changes: 48 additions & 3 deletions pkg/sidecar-controller/groupsnapshot_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,11 @@ func (ctrl *csiSnapshotSideCarController) createGroupSnapshotWrapper(groupSnapsh
creationTime = time.Now()
}

groupSnapshotSecret, err := utils.GetSecretReference(utils.GroupSnapshotterSecretParams, class.Parameters, groupSnapshotContent.GetObjectMeta().GetName(), nil)
if err != nil {
klog.Errorf("Failed to get secret reference for group snapshot content %s: %v", groupSnapshotContent.Name, err)
return groupSnapshotContent, fmt.Errorf("failed to get secret reference for group snapshot content %s: %v", groupSnapshotContent.Name, err)
}
// Create individual snapshots and snapshot contents
var snapshotContentNames []string
for _, snapshot := range snapshots {
Expand Down Expand Up @@ -452,6 +457,13 @@ func (ctrl *csiSnapshotSideCarController) createGroupSnapshotWrapper(groupSnapsh
},
}

if groupSnapshotSecret != nil {
klog.V(5).Infof("createGroupSnapshotContent: set annotation [%s] on content [%s].", utils.AnnDeletionSecretRefName, volumeSnapshotContent.Name)
metav1.SetMetaDataAnnotation(&volumeSnapshotContent.ObjectMeta, utils.AnnDeletionSecretRefName, groupSnapshotSecret.Name)

klog.V(5).Infof("createGroupSnapshotContent: set annotation [%s] on content [%s].", utils.AnnDeletionSecretRefNamespace, volumeSnapshotContent.Name)
metav1.SetMetaDataAnnotation(&volumeSnapshotContent.ObjectMeta, utils.AnnDeletionSecretRefNamespace, groupSnapshotSecret.Namespace)
}
label := make(map[string]string)
label["volumeGroupSnapshotName"] = groupSnapshotContent.Spec.VolumeGroupSnapshotRef.Name
volumeSnapshot := &crdv1.VolumeSnapshot{
Expand Down Expand Up @@ -498,7 +510,7 @@ func (ctrl *csiSnapshotSideCarController) createGroupSnapshotWrapper(groupSnapsh

func (ctrl *csiSnapshotSideCarController) getCSIGroupSnapshotInput(groupSnapshotContent *crdv1alpha1.VolumeGroupSnapshotContent) (*crdv1alpha1.VolumeGroupSnapshotClass, map[string]string, error) {
className := groupSnapshotContent.Spec.VolumeGroupSnapshotClassName
klog.V(5).Infof("getCSIGroupSnapshotInput for group snapshot content [%s]", groupSnapshotContent.Name)
klog.V(5).Infof("getCSIGroupSnapshotInput for group snapshot content %s", groupSnapshotContent.Name)
var class *crdv1alpha1.VolumeGroupSnapshotClass
var err error
if className != nil {
Expand All @@ -517,9 +529,13 @@ func (ctrl *csiSnapshotSideCarController) getCSIGroupSnapshotInput(groupSnapshot
klog.V(5).Infof("getCSISnapshotInput for groupSnapshotContent [%s]: no VolumeGroupSnapshotClassName provided for pre-provisioned group snapshot", groupSnapshotContent.Name)
}

// TODO: Resolve snapshotting secret credentials.
// Resolve snapshotting secret credentials.
snapshotterCredentials, err := ctrl.GetGroupCredentialsFromAnnotation(groupSnapshotContent)
if err != nil {
return nil, nil, err
}

return class, nil, nil
return class, snapshotterCredentials, nil
}

// getGroupSnapshotClass is a helper function to get group snapshot class from the class name.
Expand Down Expand Up @@ -826,3 +842,32 @@ func (ctrl *csiSnapshotSideCarController) checkandUpdateGroupSnapshotContentStat
}
return ctrl.createGroupSnapshotWrapper(groupSnapshotContent)
}

func (ctrl *csiSnapshotSideCarController) GetGroupCredentialsFromAnnotation(content *crdv1alpha1.VolumeGroupSnapshotContent) (map[string]string, error) {
var groupSnapshotterCredentials map[string]string
var err error

// Check if annotation exists
if metav1.HasAnnotation(content.ObjectMeta, utils.AnnDeletionSecretRefName) && metav1.HasAnnotation(content.ObjectMeta, utils.AnnDeletionSecretRefNamespace) {
annDeletionSecretName := content.Annotations[utils.AnnDeletionSecretRefName]
annDeletionSecretNamespace := content.Annotations[utils.AnnDeletionSecretRefNamespace]

groupSnapshotterSecretRef := &v1.SecretReference{}

if annDeletionSecretName == "" || annDeletionSecretNamespace == "" {
return nil, fmt.Errorf("cannot retrieve secrets for volume group snapshot content %#v, err: secret name or namespace not specified", content.Name)
}

groupSnapshotterSecretRef.Name = annDeletionSecretName
groupSnapshotterSecretRef.Namespace = annDeletionSecretNamespace

groupSnapshotterCredentials, err = utils.GetCredentials(ctrl.client, groupSnapshotterSecretRef)
if err != nil {
// Continue with deletion, as the secret may have already been deleted.
klog.Errorf("Failed to get credentials for snapshot %s: %s", content.Name, err.Error())
return nil, fmt.Errorf("cannot get credentials for snapshot content %#v", content.Name)
}
}

return groupSnapshotterCredentials, nil
}
64 changes: 64 additions & 0 deletions pkg/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ const (
PrefixedSnapshotterSecretNameKey = csiParameterPrefix + "snapshotter-secret-name" // Prefixed name key for DeleteSnapshot secret
PrefixedSnapshotterSecretNamespaceKey = csiParameterPrefix + "snapshotter-secret-namespace" // Prefixed namespace key for DeleteSnapshot secret

PrefixedGroupSnapshotterSecretNameKey = csiParameterPrefix + "group-snapshotter-secret-name" // Prefixed name key for CreateGroupSnapshot secret
PrefixedGroupSnapshotterSecretNamespaceKey = csiParameterPrefix + "group-snapshotter-secret-namespace" // Prefixed namespace key for DeleteGroupSnapshot secret

PrefixedSnapshotterListSecretNameKey = csiParameterPrefix + "snapshotter-list-secret-name" // Prefixed name key for ListSnapshots secret
PrefixedSnapshotterListSecretNamespaceKey = csiParameterPrefix + "snapshotter-list-secret-namespace" // Prefixed namespace key for ListSnapshots secret

Expand Down Expand Up @@ -150,6 +153,12 @@ var SnapshotterSecretParams = secretParamsMap{
secretNamespaceKey: PrefixedSnapshotterSecretNamespaceKey,
}

var GroupSnapshotterSecretParams = secretParamsMap{
name: "Snapshotter",
secretNameKey: PrefixedGroupSnapshotterSecretNameKey,
secretNamespaceKey: PrefixedGroupSnapshotterSecretNamespaceKey,
}

var SnapshotterListSecretParams = secretParamsMap{
name: "SnapshotterList",
secretNameKey: PrefixedSnapshotterListSecretNameKey,
Expand Down Expand Up @@ -376,6 +385,61 @@ func GetSecretReference(secretParams secretParamsMap, snapshotClassParams map[st
return ref, nil
}

// GetSecretReference for the group snapshot
func GetGroupSnapshotSecretReference(secretParams secretParamsMap, volumeGroupSnapshotClassParams map[string]string, groupSnapContentName string, volumeGroupSnapshot *crdv1alpha1.VolumeGroupSnapshot) (*v1.SecretReference, error) {
nameTemplate, namespaceTemplate, err := verifyAndGetSecretNameAndNamespaceTemplate(secretParams, volumeGroupSnapshotClassParams)
if err != nil {
return nil, fmt.Errorf("failed to get name and namespace template from params: %v", err)
}
if nameTemplate == "" && namespaceTemplate == "" {
return nil, nil
}

ref := &v1.SecretReference{}

// Secret namespace template can make use of the VolumeGroupSnapshotContent name, VolumeGroupSnapshot name or namespace.
// Note that neither of those things are under the control of the VolumeGroupSnapshot user.
namespaceParams := map[string]string{"volumegroupsnapshotcontent.name": groupSnapContentName}
// snapshot may be nil when resolving create/delete volumegroupsnapshot secret names because the
// snapshot may or may not exist at delete time
if volumeGroupSnapshot != nil {
namespaceParams["volumegroupsnapshot.namespace"] = volumeGroupSnapshot.Namespace
}

resolvedNamespace, err := resolveTemplate(namespaceTemplate, namespaceParams)
if err != nil {
return nil, fmt.Errorf("error resolving value %q: %v", namespaceTemplate, err)
}

if len(validation.IsDNS1123Label(resolvedNamespace)) > 0 {
if namespaceTemplate != resolvedNamespace {
return nil, fmt.Errorf("%q resolved to %q which is not a valid namespace name", namespaceTemplate, resolvedNamespace)
}
return nil, fmt.Errorf("%q is not a valid namespace name", namespaceTemplate)
}
ref.Namespace = resolvedNamespace

// Secret name template can make use of the VolumeGroupSnapshotContent name, VolumeGroupSnapshot name or namespace.
// Note that VolumeGroupSnapshot name and namespace are under the VolumeGroupSnapshot user's control.
nameParams := map[string]string{"volumegroupsnapshotcontent.name": groupSnapContentName}
if volumeGroupSnapshot != nil {
nameParams["volumegroupsnapshot.name"] = volumeGroupSnapshot.Name
nameParams["volumegroupsnapshot.namespace"] = volumeGroupSnapshot.Namespace
}
resolvedName, err := resolveTemplate(nameTemplate, nameParams)
if err != nil {
return nil, fmt.Errorf("error resolving value %q: %v", nameTemplate, err)
}
if len(validation.IsDNS1123Subdomain(resolvedName)) > 0 {
if nameTemplate != resolvedName {
return nil, fmt.Errorf("%q resolved to %q which is not a valid secret name", nameTemplate, resolvedName)
}
return nil, fmt.Errorf("%q is not a valid secret name", nameTemplate)
}
ref.Name = resolvedName
return ref, nil
}

// resolveTemplate resolves the template by checking if the value is missing for a key
func resolveTemplate(template string, params map[string]string) (string, error) {
missingParams := sets.NewString()
Expand Down

0 comments on commit 5e1f0b0

Please sign in to comment.