From 53a2b9859ddaaf3762fb9e150dd7c61a0f7e9b54 Mon Sep 17 00:00:00 2001 From: Bella Khizgiyaev Date: Thu, 28 Sep 2023 18:38:58 +0300 Subject: [PATCH] Delete PVC and PV from destination namespace when the plan is archived Signed-off-by: Bella Khizgiyaev --- pkg/controller/plan/BUILD.bazel | 1 + pkg/controller/plan/kubevirt.go | 91 +++++++++++++--------------- pkg/controller/plan/migration.go | 36 +++++++++++ pkg/controller/provider/ova-setup.go | 4 ++ 4 files changed, 82 insertions(+), 50 deletions(-) diff --git a/pkg/controller/plan/BUILD.bazel b/pkg/controller/plan/BUILD.bazel index 0a233c18d..b0c7511ee 100644 --- a/pkg/controller/plan/BUILD.bazel +++ b/pkg/controller/plan/BUILD.bazel @@ -50,6 +50,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/runtime", "//vendor/k8s.io/apimachinery/pkg/types", "//vendor/k8s.io/apimachinery/pkg/util/validation", + "//vendor/k8s.io/apimachinery/pkg/util/wait", "//vendor/k8s.io/apiserver/pkg/storage/names", "//vendor/k8s.io/client-go/kubernetes/scheme", "//vendor/kubevirt.io/api/core/v1:core", diff --git a/pkg/controller/plan/kubevirt.go b/pkg/controller/plan/kubevirt.go index b0dc61945..5e94a04df 100644 --- a/pkg/controller/plan/kubevirt.go +++ b/pkg/controller/plan/kubevirt.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" k8svalidation "k8s.io/apimachinery/pkg/util/validation" + "k8s.io/apimachinery/pkg/util/wait" cnv "kubevirt.io/api/core/v1" libvirtxml "libvirt.org/libvirt-go-xml" @@ -1340,17 +1341,6 @@ func (r *KubeVirt) podVolumeMounts(vmVolumes []cnv.Volume, configMap *core.Confi switch r.Source.Provider.Type() { case api.Ova: pvcName := fmt.Sprintf("ova-nfs-pvc-%s-%s", r.Source.Provider.Name, r.Plan.Name) - /* - TODO: set ownerReferences the PV and PVC deleted once the plan is done. - cross namespaces are not possible to be used for plan/provider ownership. - optional: PV+PVC per VM, deleted via cleanup. ownership: importer pod? DV? - ownerReference := meta.OwnerReference{ - APIVersion: "forklift.konveyor.io/v1beta1", - Kind: "Plan", - Name: r.Plan.Name, - UID: r.Plan.UID, - } - */ err = r.CreatePvForNfs() if err != nil { return @@ -1848,48 +1838,47 @@ func (r *KubeVirt) EnsurePersistentVolume(vmRef ref.Ref, persistentVolumes []cor return } -func (r *KubeVirt) getOvaPvNfs() (found bool, err error) { - pv := &core.PersistentVolume{} - err = r.Destination.Client.Get( +func GetOvaPvNfs(client client.Client, planName string, providerName string) (pv *core.PersistentVolume, found bool, err error) { + pv = &core.PersistentVolume{} + err = client.Get( context.TODO(), types.NamespacedName{ - Name: fmt.Sprintf("ova-nfs-pv-%s", r.Plan.Name), + Name: fmt.Sprintf("ova-nfs-pv-%s-%s", providerName, planName), }, pv, ) if err != nil { if k8serr.IsNotFound(err) { - return false, nil + return nil, false, nil } err = liberr.Wrap(err) return } - return true, nil + return } -func (r *KubeVirt) getOvaPvcNfs() (found bool, err error) { - pvc := &core.PersistentVolumeClaim{} - err = r.Destination.Client.Get( +func GetOvaPvcNfs(client client.Client, planName string, planNamespace string, providerName string) (pvc *core.PersistentVolumeClaim, found bool, err error) { + pvc = &core.PersistentVolumeClaim{} + err = client.Get( context.TODO(), types.NamespacedName{ - Name: fmt.Sprintf("ova-nfs-pvc-%s-%s", r.Source.Provider.Name, r.Plan.Name), - Namespace: r.Plan.Spec.TargetNamespace, + Name: fmt.Sprintf("ova-nfs-pvc-%s-%s", providerName, planName), + Namespace: planNamespace, }, pvc, ) if err != nil { if k8serr.IsNotFound(err) { - return false, nil + return nil, false, nil } err = liberr.Wrap(err) return } - return true, nil + return } -// TODO if we use ownership get it to the method func (r *KubeVirt) CreatePvForNfs() (err error) { sourceProvider := r.Source.Provider splitted := strings.Split(sourceProvider.Spec.URL, ":") @@ -1900,9 +1889,10 @@ func (r *KubeVirt) CreatePvForNfs() (err error) { nfsServer := splitted[0] nfsPath := splitted[1] - pvName := fmt.Sprintf("ova-nfs-pv-%s", r.Plan.Name) - found, err := r.getOvaPvNfs() + pvName := fmt.Sprintf("ova-nfs-pv-%s-%s", r.Source.Provider.Name, r.Plan.Name) + _, found, err := GetOvaPvNfs(r.Destination.Client, r.Plan.Name, r.Plan.Provider.Source.Name) if err != nil { + r.Log.Error(err, "Failed to get ova PV") return } if found { @@ -1910,10 +1900,11 @@ func (r *KubeVirt) CreatePvForNfs() (err error) { return } + labels := map[string]string{"providerName": r.Plan.Provider.Source.Name, "app": "forklift", "migration": r.Migration.Name, "plan": r.Plan.Name} pv := &core.PersistentVolume{ ObjectMeta: meta.ObjectMeta{ - Name: pvName, - // OwnerReferences: []meta.OwnerReference{ownerReference}, + Name: pvName, + Labels: labels, }, Spec: core.PersistentVolumeSpec{ Capacity: core.ResourceList{ @@ -1938,10 +1929,10 @@ func (r *KubeVirt) CreatePvForNfs() (err error) { return } -// TODO if we use ownership get it to the method func (r *KubeVirt) CreatePvcForNfs(pvcName string) (err error) { - found, err := r.getOvaPvcNfs() + _, found, err := GetOvaPvcNfs(r.Destination.Client, r.Plan.Name, r.Plan.Spec.TargetNamespace, r.Plan.Provider.Source.Name) if err != nil { + r.Log.Error(err, "Failed to get ova PVC") return } if found { @@ -1950,12 +1941,13 @@ func (r *KubeVirt) CreatePvcForNfs(pvcName string) (err error) { } sc := "" - pvName := fmt.Sprintf("ova-nfs-pv-%s", r.Plan.Name) + pvName := fmt.Sprintf("ova-nfs-pv-%s-%s", r.Source.Provider.Name, r.Plan.Name) + labels := map[string]string{"providerName": r.Plan.Provider.Source.Name, "app": "forklift", "migration": r.Migration.Name, "plan": r.Plan.Name} pvc := &core.PersistentVolumeClaim{ ObjectMeta: meta.ObjectMeta{ Name: pvcName, Namespace: r.Plan.Spec.TargetNamespace, - // OwnerReferences: []meta.OwnerReference{ownerReference}, + Labels: labels, }, Spec: core.PersistentVolumeClaimSpec{ Resources: core.ResourceRequirements{ @@ -1976,30 +1968,29 @@ func (r *KubeVirt) CreatePvcForNfs(pvcName string) (err error) { return } - // wait until pvc and pv are bounded. - timeout := time.After(5 * time.Minute) - tick := time.Tick(5 * time.Second) pvcNamespacedName := types.NamespacedName{ Namespace: r.Plan.Spec.TargetNamespace, Name: pvcName, } - for { - select { - case <-timeout: - r.Log.Error(err, "Timed out waiting for PVC to be bound") - return fmt.Errorf("timeout passed waiting for the OVA PVC %v", pvc) - case <-tick: - err = r.Get(context.TODO(), pvcNamespacedName, pvc) - if err != nil { - r.Log.Error(err, "Failed to bound OVA plan PVC") - return - } - if pvc.Status.Phase == "Bound" { - return - } + if err = wait.PollUntilContextTimeout(context.TODO(), 5*time.Second, 15*time.Second, true, func(ctx context.Context) (done bool, err error) { + err = r.Get(context.TODO(), pvcNamespacedName, pvc) + if err != nil { + r.Log.Error(err, "Failed to get OVA plan PVC") + return false, err + } + + if pvc.Status.Phase == "Bound" { + return true, nil } + return false, nil + + }); err != nil { + r.Log.Error(err, "Failed to bound OVA PVC to PV ") + return + } + return nil } // Ensure the PV exist on the destination. diff --git a/pkg/controller/plan/migration.go b/pkg/controller/plan/migration.go index f3f060b1e..5682ad64b 100644 --- a/pkg/controller/plan/migration.go +++ b/pkg/controller/plan/migration.go @@ -12,6 +12,7 @@ import ( "strings" "time" + "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1" "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan" "github.com/konveyor/forklift-controller/pkg/controller/plan/adapter" plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context" @@ -336,6 +337,41 @@ func (r *Migration) Archive() { return } + if r.Plan.Provider.Source.Type() == v1beta1.Ova { + //delete pvc and pv + pvc, _, errPvc := GetOvaPvcNfs(r.Destination.Client, r.Plan.Name, r.Plan.Spec.TargetNamespace, r.Plan.Provider.Source.Name) + if errPvc != nil { + r.Log.Error(err, "Failed to get the plan PVC") + return + } + // The PVC was alredy deleted + if pvc == nil { + return + } + + err = r.Destination.Client.Delete(context.TODO(), pvc) + if err != nil { + r.Log.Error(err, "Failed to delete the plan PVC") + return + } + + pv, _, errPv := GetOvaPvNfs(r.Destination.Client, r.Plan.Name, r.Plan.Provider.Source.Name) + if errPv != nil { + r.Log.Error(err, "Failed to get the plan PV") + return + } + // The PV was alredy deleted + if pv == nil { + return + } + + err = r.Destination.Client.Delete(context.TODO(), pv) + if err != nil { + r.Log.Error(err, "Failed to delete the plan PV") + return + } + } + for _, vm := range r.Plan.Status.Migration.VMs { err = r.CleanUp(vm) if err != nil { diff --git a/pkg/controller/provider/ova-setup.go b/pkg/controller/provider/ova-setup.go index 6933cd823..db3f640f8 100644 --- a/pkg/controller/provider/ova-setup.go +++ b/pkg/controller/provider/ova-setup.go @@ -65,11 +65,13 @@ func (r *Reconciler) createPvForNfs(provider *api.Provider, ctx context.Context, } nfsServer := splitted[0] nfsPath := splitted[1] + labels := map[string]string{"providerName": provider.Name, "app": "forklift"} pv := &core.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: pvName, OwnerReferences: []metav1.OwnerReference{ownerReference}, + Labels: labels, }, Spec: core.PersistentVolumeSpec{ Capacity: core.ResourceList{ @@ -95,11 +97,13 @@ func (r *Reconciler) createPvForNfs(provider *api.Provider, ctx context.Context, func (r *Reconciler) createPvcForNfs(provider *api.Provider, ctx context.Context, ownerReference metav1.OwnerReference, pvName, pvcName string) (err error) { sc := "" + labels := map[string]string{"providerName": provider.Name, "app": "forklift"} pvc := &core.PersistentVolumeClaim{ ObjectMeta: metav1.ObjectMeta{ Name: pvcName, Namespace: provider.Namespace, OwnerReferences: []metav1.OwnerReference{ownerReference}, + Labels: labels, }, Spec: core.PersistentVolumeClaimSpec{ Resources: core.ResourceRequirements{