Skip to content

Commit

Permalink
DataVolume clone from snapshot uses populator
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Henriksen <mhenriks@redhat.com>
  • Loading branch information
mhenriks committed Jun 16, 2023
1 parent ac7a342 commit 9da9c01
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 103 deletions.
1 change: 1 addition & 0 deletions pkg/controller/datavolume/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ go_library(
"//vendor/k8s.io/client-go/tools/cache:go_default_library",
"//vendor/k8s.io/client-go/tools/record:go_default_library",
"//vendor/k8s.io/component-helpers/storage/volume:go_default_library",
"//vendor/k8s.io/utils/pointer:go_default_library",
"//vendor/sigs.k8s.io/controller-runtime/pkg/client:go_default_library",
"//vendor/sigs.k8s.io/controller-runtime/pkg/controller:go_default_library",
"//vendor/sigs.k8s.io/controller-runtime/pkg/controller/controllerutil:go_default_library",
Expand Down
83 changes: 75 additions & 8 deletions pkg/controller/datavolume/clone-controller-base.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,11 +130,77 @@ const (
// CloneReconcilerBase members
type CloneReconcilerBase struct {
ReconcilerBase
clonerImage string
importerImage string
pullPolicy string
tokenValidator token.Validator
tokenGenerator token.Generator
clonerImage string
importerImage string
pullPolicy string
cloneSourceAPIGroup *string
cloneSourceKind string
tokenValidator token.Validator
tokenGenerator token.Generator
}

func (r *CloneReconcilerBase) addVolumeCloneSourceWatch(datavolumeController controller.Controller) error {
return datavolumeController.Watch(&source.Kind{Type: &cdiv1.VolumeCloneSource{}}, handler.EnqueueRequestsFromMapFunc(
func(obj client.Object) []reconcile.Request {
var err error
var hasDataVolumeOwner bool
var ownerNamespace, ownerName string
ownerRef := metav1.GetControllerOf(obj)
if ownerRef != nil && ownerRef.Kind == "DataVolume" {
hasDataVolumeOwner = true
ownerNamespace = obj.GetNamespace()
ownerName = obj.GetName()
} else if hasAnnOwnedByDataVolume(obj) {
hasDataVolumeOwner = true
ownerNamespace, ownerName, err = getAnnOwnedByDataVolume(obj)
if err != nil {
return nil
}
}
if !hasDataVolumeOwner {
return nil
}
dv := &cdiv1.DataVolume{
ObjectMeta: metav1.ObjectMeta{
Namespace: ownerNamespace,
Name: ownerName,
},
}
if err = r.client.Get(context.TODO(), client.ObjectKeyFromObject(dv), dv); err != nil {
r.log.Info("Failed to get DataVolume", "error", err)
return nil
}
if err := r.populateSourceIfSourceRef(dv); err != nil {
r.log.Info("Failed to check DataSource", "error", err)
return nil
}
if (r.cloneSourceKind == "PersistentVolumeClaim" && dv.Spec.Source.PVC != nil) ||
(r.cloneSourceKind == "VolumeSnapshot" && dv.Spec.Source.Snapshot != nil) {
return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: ownerNamespace, Name: ownerName}}}
}
return nil
}),
)
}

func (r *CloneReconcilerBase) updatePVCForPopulation(dataVolume *cdiv1.DataVolume, pvc *corev1.PersistentVolumeClaim) error {
if dataVolume.Spec.Source.PVC == nil && dataVolume.Spec.Source.Snapshot == nil {
return errors.Errorf("no source set for clone datavolume")
}
if err := addCloneToken(dataVolume, pvc); err != nil {
return err
}
if isCrossNamespaceClone(dataVolume) {
_, _, sourcNamespace := cc.GetCloneSourceInfo(dataVolume)
cc.AddAnnotation(pvc, populators.AnnDataSourceNamespace, sourcNamespace)
}
apiGroup := cc.AnnAPIGroup
pvc.Spec.DataSourceRef = &corev1.TypedObjectReference{
APIGroup: &apiGroup,
Kind: cdiv1.VolumeCloneSourceRef,
Name: volumeCloneSourceName(dataVolume),
}
return nil
}

func (r *CloneReconcilerBase) ensureExtendedToken(pvc *corev1.PersistentVolumeClaim) error {
Expand Down Expand Up @@ -172,7 +238,7 @@ func (r *CloneReconcilerBase) ensureExtendedToken(pvc *corev1.PersistentVolumeCl
return nil
}

func (r *CloneReconcilerBase) reconcileVolumeCloneSourceCR(syncState *dvSyncState, kind string) error {
func (r *CloneReconcilerBase) reconcileVolumeCloneSourceCR(syncState *dvSyncState) error {
dv := syncState.dvMutated
volumeCloneSource := &cdiv1.VolumeCloneSource{}
volumeCloneSourceName := volumeCloneSourceName(dv)
Expand Down Expand Up @@ -206,8 +272,9 @@ func (r *CloneReconcilerBase) reconcileVolumeCloneSourceCR(syncState *dvSyncStat
},
Spec: cdiv1.VolumeCloneSourceSpec{
Source: corev1.TypedLocalObjectReference{
Kind: "PersistentVolumeClaim",
Name: sourceName,
APIGroup: r.cloneSourceAPIGroup,
Kind: r.cloneSourceKind,
Name: sourceName,
},
Preallocation: dv.Spec.Preallocation,
},
Expand Down
3 changes: 1 addition & 2 deletions pkg/controller/datavolume/controller-base.go
Original file line number Diff line number Diff line change
Expand Up @@ -1208,8 +1208,7 @@ func (r *ReconcilerBase) shouldUseCDIPopulator(syncState *dvSyncState) (bool, er
// currently we don't support populator with import source of VDDK or Imageio
// or clone either from PVC nor snapshot
if dv.Spec.Source.Imageio != nil ||
dv.Spec.Source.VDDK != nil ||
dv.Spec.Source.Snapshot != nil {
dv.Spec.Source.VDDK != nil {
return false, nil
}

Expand Down
3 changes: 0 additions & 3 deletions pkg/controller/datavolume/import-controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1584,9 +1584,6 @@ var _ = Describe("All DataVolume Tests", func() {
Entry("VDDK", &cdiv1.DataVolumeSource{
VDDK: &cdiv1.DataVolumeSourceVDDK{},
}),
Entry("Snapshot", &cdiv1.DataVolumeSource{
Snapshot: &cdiv1.DataVolumeSourceSnapshot{},
}),
)

It("Should return false if storage class has wffc bindingMode and honorWaitForFirstConsumer feature gate is disabled", func() {
Expand Down
57 changes: 10 additions & 47 deletions pkg/controller/datavolume/pvc-clone-controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ import (
cdiv1 "kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1"
"kubevirt.io/containerized-data-importer/pkg/common"
cc "kubevirt.io/containerized-data-importer/pkg/controller/common"
"kubevirt.io/containerized-data-importer/pkg/controller/populators"
featuregates "kubevirt.io/containerized-data-importer/pkg/feature-gates"
)

Expand Down Expand Up @@ -86,10 +85,11 @@ func NewPvcCloneController(
installerLabels: installerLabels,
shouldUpdateProgress: true,
},
clonerImage: clonerImage,
importerImage: importerImage,
pullPolicy: pullPolicy,
tokenValidator: cc.NewCloneTokenValidator(common.CloneTokenIssuer, tokenPublicKey),
clonerImage: clonerImage,
importerImage: importerImage,
pullPolicy: pullPolicy,
cloneSourceKind: "PersistentVolumeClaim",
tokenValidator: cc.NewCloneTokenValidator(common.CloneTokenIssuer, tokenPublicKey),
// for long term tokens to handle cross namespace dumb clones
tokenGenerator: newLongTermCloneTokenGenerator(tokenPrivateKey),
},
Expand All @@ -102,14 +102,14 @@ func NewPvcCloneController(
return nil, err
}

if err = addDataVolumeCloneControllerWatches(mgr, dataVolumeCloneController); err != nil {
if err = reconciler.addDataVolumeCloneControllerWatches(mgr, dataVolumeCloneController); err != nil {
return nil, err
}

return dataVolumeCloneController, nil
}

func addDataVolumeCloneControllerWatches(mgr manager.Manager, datavolumeController controller.Controller) error {
func (r *PvcCloneReconciler) addDataVolumeCloneControllerWatches(mgr manager.Manager, datavolumeController controller.Controller) error {
if err := addDataVolumeControllerCommonWatches(mgr, datavolumeController, dataVolumePvcClone); err != nil {
return err
}
Expand All @@ -123,25 +123,7 @@ func addDataVolumeCloneControllerWatches(mgr manager.Manager, datavolumeControll
return err
}

if err := datavolumeController.Watch(&source.Kind{Type: &cdiv1.VolumeCloneSource{}}, &handler.EnqueueRequestForOwner{
OwnerType: &cdiv1.DataVolume{},
IsController: true,
}); err != nil {
return err
}

if err := datavolumeController.Watch(&source.Kind{Type: &cdiv1.VolumeCloneSource{}}, handler.EnqueueRequestsFromMapFunc(
func(obj client.Object) []reconcile.Request {
if !hasAnnOwnedByDataVolume(obj) {
return nil
}
namespace, name, err := getAnnOwnedByDataVolume(obj)
if err != nil {
return nil
}
return []reconcile.Request{{NamespacedName: types.NamespacedName{Namespace: namespace, Name: name}}}
}),
); err != nil {
if err := r.addVolumeCloneSourceWatch(datavolumeController); err != nil {
return err
}

Expand Down Expand Up @@ -213,7 +195,7 @@ func (r *PvcCloneReconciler) cleanup(syncState *dvSyncState) error {
return nil
}

return r.reconcileVolumeCloneSourceCR(syncState, "PersistentVolumeClaim")
return r.reconcileVolumeCloneSourceCR(syncState)
}

func addCloneToken(dv *cdiv1.DataVolume, pvc *corev1.PersistentVolumeClaim) error {
Expand All @@ -229,25 +211,6 @@ func volumeCloneSourceName(dv *cdiv1.DataVolume) string {
return fmt.Sprintf("%s-%s", volumeCloneSourcePrefix, dv.UID)
}

func (r *PvcCloneReconciler) updatePVCForPopulation(dataVolume *cdiv1.DataVolume, pvc *corev1.PersistentVolumeClaim) error {
if dataVolume.Spec.Source.PVC == nil {
return errors.Errorf("no source set for clone datavolume")
}
if err := addCloneToken(dataVolume, pvc); err != nil {
return err
}
if isCrossNamespaceClone(dataVolume) {
cc.AddAnnotation(pvc, populators.AnnDataSourceNamespace, dataVolume.Spec.Source.PVC.Namespace)
}
apiGroup := cc.AnnAPIGroup
pvc.Spec.DataSourceRef = &corev1.TypedObjectReference{
APIGroup: &apiGroup,
Kind: cdiv1.VolumeCloneSourceRef,
Name: volumeCloneSourceName(dataVolume),
}
return nil
}

func (r *PvcCloneReconciler) updateAnnotations(dataVolume *cdiv1.DataVolume, pvc *corev1.PersistentVolumeClaim) error {
if dataVolume.Spec.Source.PVC == nil {
return errors.Errorf("no source set for clone datavolume")
Expand Down Expand Up @@ -347,7 +310,7 @@ func (r *PvcCloneReconciler) syncClone(log logr.Logger, req reconcile.Request) (
}

if syncRes.usePopulator {
if err := r.reconcileVolumeCloneSourceCR(&syncRes, "PersistentVolumeClaim"); err != nil {
if err := r.reconcileVolumeCloneSourceCR(&syncRes); err != nil {
return syncRes, err
}

Expand Down
Loading

0 comments on commit 9da9c01

Please sign in to comment.