Skip to content

Commit

Permalink
Delete PVC and PV from destination namespace when the plan is archived
Browse files Browse the repository at this point in the history
Signed-off-by: Bella Khizgiyaev <[email protected]>
  • Loading branch information
bkhizgiy committed Oct 3, 2023
1 parent 1760225 commit 083bbac
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 50 deletions.
1 change: 1 addition & 0 deletions pkg/controller/plan/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
92 changes: 42 additions & 50 deletions pkg/controller/plan/kubevirt.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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, ":")
Expand All @@ -1900,20 +1889,22 @@ 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 {
r.Log.Info("The PV for OVA NFS exists", "PV", pvName)
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{
Expand All @@ -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 {
Expand All @@ -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{
Expand All @@ -1976,30 +1968,30 @@ 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
}
// wait until pvc and pv are bounded.
err = wait.PollImmediateUntil(5*time.Second, func() (bool, error) {

Check failure on line 1977 in pkg/controller/plan/kubevirt.go

View workflow job for this annotation

GitHub Actions / lint

SA1019: wait.PollImmediateUntil is deprecated: This method does not return errors from context, use PollWithContextCancel. Note that the new method will no longer return ErrWaitTimeout and instead return errors defined by the context package. Will be removed in a future release. (staticcheck)
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
}, context.TODO().Done())
if err != nil {
r.Log.Error(err, "Failed to bound OVA PVC to PV ")
return
}

return nil
}

// Ensure the PV exist on the destination.
Expand Down
36 changes: 36 additions & 0 deletions pkg/controller/plan/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions pkg/controller/provider/ova-setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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{
Expand Down

0 comments on commit 083bbac

Please sign in to comment.