Skip to content

Commit

Permalink
Support CDI CRs
Browse files Browse the repository at this point in the history
Signed-off-by: Benny Zlotnik <[email protected]>
  • Loading branch information
bennyz committed May 28, 2024
1 parent bfc78cb commit e0b1d66
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 8 deletions.
1 change: 1 addition & 0 deletions operator/config/rbac/forklift-controller_role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ metadata:
rules:
- apiGroups:
- forklift.konveyor.io
- forklift.cdi.konveyor.io
resources:
- '*'
verbs:
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/plan/adapter/ovirt/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ go_library(
"//pkg/controller/provider/web/base",
"//pkg/controller/provider/web/ocp",
"//pkg/controller/provider/web/ovirt",
"//pkg/lib/client/openshift",
"//pkg/lib/error",
"//pkg/lib/itinerary",
"//pkg/settings",
Expand All @@ -33,7 +34,11 @@ go_library(
"//vendor/k8s.io/apimachinery/pkg/api/resource",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:meta",
"//vendor/k8s.io/apimachinery/pkg/labels",
"//vendor/k8s.io/apimachinery/pkg/runtime",
"//vendor/k8s.io/apimachinery/pkg/runtime/schema",
"//vendor/k8s.io/apimachinery/pkg/types",
"//vendor/k8s.io/client-go/dynamic",
"//vendor/k8s.io/client-go/kubernetes",
"//vendor/kubevirt.io/api/core/v1:core",
"//vendor/kubevirt.io/containerized-data-importer-api/pkg/apis/core/v1beta1",
"//vendor/sigs.k8s.io/controller-runtime/pkg/client",
Expand Down
79 changes: 78 additions & 1 deletion pkg/controller/plan/adapter/ovirt/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ import (

"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1"
api "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1"
ocpclient "github.com/konveyor/forklift-controller/pkg/lib/client/openshift"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/kubernetes"

"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan"
"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref"
Expand Down Expand Up @@ -712,6 +715,8 @@ func (r *Builder) PopulatorVolumes(vmRef ref.Ref, annotations map[string]string,
return
}

r.Log.Info("Benny PopulatorVolumes", "workload", workload)

var sdToStorageClass map[string]string
for _, diskAttachment := range workload.DiskAttachments {
if diskAttachment.Disk.StorageType == "lun" {
Expand Down Expand Up @@ -765,18 +770,38 @@ func (r *Builder) mapStorageDomainToStorageClass() (map[string]string, error) {

// Get the OvirtVolumePopulator CustomResource based on the disk ID.
func (r *Builder) getVolumePopulator(diskID string) (populatorCr api.OvirtVolumePopulator, err error) {
apiGroup, err := r.calculateAPIGroup()
if err != nil {
err = liberr.Wrap(err)
return
}

gvk := schema.GroupVersionKind{
Group: apiGroup,
Version: "v1", // Adjust the version if necessary
Kind: "OvirtVolumePopulatorList",
}

r.Log.Info("Benny OvirtVolumePopulatorList", "apiGroup", apiGroup, "gvk", gvk)
list := api.OvirtVolumePopulatorList{}
err = r.Destination.Client.List(context.TODO(), &list, &client.ListOptions{
Namespace: r.Plan.Spec.TargetNamespace,
LabelSelector: labels.SelectorFromSet(map[string]string{
"migration": string(r.Migration.UID),
"diskID": diskID,
}),
Raw: &meta.ListOptions{
TypeMeta: meta.TypeMeta{
APIVersion: gvk.GroupVersion().String(),
Kind: gvk.Kind,
},
},
})
if err != nil {
err = liberr.Wrap(err)
return
}
r.Log.Info("using API group", "apiGroup", apiGroup)

if len(list.Items) == 0 {
err = k8serr.NewNotFound(api.SchemeGroupVersion.WithResource("OvirtVolumePopulator").GroupResource(), diskID)
Expand All @@ -803,7 +828,19 @@ func (r *Builder) createVolumePopulatorCR(diskAttachment model.XDiskAttachment,
Scheme: providerURL.Scheme,
Host: providerURL.Host,
}

apiGroup, err := r.calculateAPIGroup()
if err != nil {
err = liberr.Wrap(err)
return
}
r.Log.Info("using API group", "apiGroup", apiGroup)

populatorCR := &api.OvirtVolumePopulator{
TypeMeta: meta.TypeMeta{
Kind: api.OvirtVolumePopulatorKind,
APIVersion: apiGroup,
},
ObjectMeta: meta.ObjectMeta{
GenerateName: fmt.Sprintf("%s-", diskAttachment.DiskAttachment.ID),
Namespace: r.Plan.Spec.TargetNamespace,
Expand Down Expand Up @@ -874,6 +911,14 @@ func (r *Builder) persistentVolumeClaimWithSourceRef(diskAttachment model.XDiskA

annotations[planbase.AnnDiskSource] = diskAttachment.ID

apiGroup, err := r.calculateAPIGroup()
if err != nil {
err = liberr.Wrap(err)
return
}

r.Log.Info("using API group", "apiGroup", apiGroup)

pvc = &core.PersistentVolumeClaim{
ObjectMeta: meta.ObjectMeta{
GenerateName: fmt.Sprintf("%s-", diskAttachment.DiskAttachment.ID),
Expand All @@ -894,7 +939,7 @@ func (r *Builder) persistentVolumeClaimWithSourceRef(diskAttachment model.XDiskA
StorageClassName: &storageClassName,
VolumeMode: volumeMode,
DataSourceRef: &core.TypedObjectReference{
APIGroup: &api.SchemeGroupVersion.Group,
APIGroup: &apiGroup,
Kind: v1beta1.OvirtVolumePopulatorKind,
Name: populatorName,
},
Expand All @@ -905,6 +950,38 @@ func (r *Builder) persistentVolumeClaimWithSourceRef(diskAttachment model.XDiskA
return
}

func (r *Builder) calculateAPIGroup() (string, error) {
// If OCP version is >= 4.16 use forklift.cdi.konveyor.io
// Otherwise use forklift.konveyor.io
restCfg := ocpclient.RestCfg(r.Source.Provider, r.Plan.Referenced.Secret)
clientset, err := kubernetes.NewForConfig(restCfg)
if err != nil {
return "", liberr.Wrap(err)
}

discoveryClient := clientset.Discovery()
version, err := discoveryClient.ServerVersion()
if err != nil {
return "", liberr.Wrap(err)
}

major, err := strconv.Atoi(version.Major)
if err != nil {
return "", liberr.Wrap(err)
}

minor, err := strconv.Atoi(version.Minor)
if err != nil {
return "", liberr.Wrap(err)
}

if major < 1 || (major == 1 && minor <= 28) {
return "forklift.konveyor.io", nil
}

return "forklift.cdi.konveyor.io", nil
}

func (r *Builder) PopulatorTransferredBytes(pvc *core.PersistentVolumeClaim) (transferredBytes int64, err error) {
if _, ok := pvc.Annotations["lun"]; ok {
// skip LUNs
Expand Down
96 changes: 89 additions & 7 deletions pkg/controller/plan/adapter/ovirt/destinationclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,21 @@ package ovirt
import (
"context"
"path"
"strconv"

"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1"
"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/plan"
plancontext "github.com/konveyor/forklift-controller/pkg/controller/plan/context"
ocpclient "github.com/konveyor/forklift-controller/pkg/lib/client/openshift"
liberr "github.com/konveyor/forklift-controller/pkg/lib/error"
core "k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
meta "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
"k8s.io/client-go/kubernetes"
"sigs.k8s.io/controller-runtime/pkg/client"
k8sutil "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)
Expand All @@ -21,10 +28,12 @@ type DestinationClient struct {

// Delete OvirtVolumePopulator CustomResource list.
func (r *DestinationClient) DeletePopulatorDataSource(vm *plan.VMStatus) error {
r.Log.Info("Benny - DeletePopulatorDataSource")
populatorCrList, err := r.getPopulatorCrList()
if err != nil {
return liberr.Wrap(err)
}
r.Log.Info("Benny - DeletePopulatorDataSource", "populatorCrList", populatorCrList)
for _, populatorCr := range populatorCrList.Items {
err = r.DeleteObject(&populatorCr, vm, "Deleted OvirtPopulator CR.", "OvirtVolumePopulator")
if err != nil {
Expand Down Expand Up @@ -61,16 +70,89 @@ func (r *DestinationClient) SetPopulatorCrOwnership() (err error) {
return
}

func (r *DestinationClient) calculateAPIGroup(kind string) (*schema.GroupVersionKind, error) {
// If OCP version is >= 4.16 use forklift.cdi.konveyor.io
// Otherwise use forklift.konveyor.io
r.Log.Info("Benny calculateAPIGroup")
restCfg := ocpclient.RestCfg(r.Destination.Provider, r.Plan.Referenced.Secret)
r.Log.Info("Benny Rest", "restCfg", restCfg)
clientset, err := kubernetes.NewForConfig(restCfg)
if err != nil {
return nil, liberr.Wrap(err)
}

r.Log.Info("Benny Before discoveryClient.ServerVersion()")

discoveryClient := clientset.Discovery()
version, err := discoveryClient.ServerVersion()
if err != nil {
r.Log.Info("Benny ServerVersion() error", "error", err)

return nil, liberr.Wrap(err)
}

r.Log.Info("Benny calculateAPIGroup after discoveryClient.ServerVersion()")

major, err := strconv.Atoi(version.Major)
if err != nil {
return nil, liberr.Wrap(err)
}

minor, err := strconv.Atoi(version.Minor)
if err != nil {
return nil, liberr.Wrap(err)
}

r.Log.Info("Benny calculateAPIGroup before return")

if major < 1 || (major == 1 && minor <= 28) {
return &schema.GroupVersionKind{Group: "forklift.konveyor.io", Version: "v1beta1", Kind: kind}, nil
}

return &schema.GroupVersionKind{Group: "forklift.cdi.konveyor.io", Version: "v1beta1", Kind: kind}, nil
}

// Get the OvirtVolumePopulator CustomResource List.
// Get the OvirtVolumePopulator CustomResource List.
func (r *DestinationClient) getPopulatorCrList() (populatorCrList v1beta1.OvirtVolumePopulatorList, err error) {
r.Log.Info("Getting OvirtVolumePopulatorList")
populatorCrList = v1beta1.OvirtVolumePopulatorList{}
err = r.Destination.Client.List(
context.TODO(),
&populatorCrList,
&client.ListOptions{
Namespace: r.Plan.Spec.TargetNamespace,
LabelSelector: labels.SelectorFromSet(map[string]string{"migration": string(r.Plan.Status.Migration.ActiveSnapshot().Migration.UID)}),
})
gvk, err := r.calculateAPIGroup("OvirtVolumePopulator")
if err != nil {
r.Log.Info("Error calculating API group", "error", err)
return
}
r.Log.Info("API Group", "apiGroup", gvk)

// Create a dynamic client using the correct GVK
dynamicClient, err := dynamic.NewForConfig(ocpclient.RestCfg(r.Destination.Provider, r.Plan.Referenced.Secret))
if err != nil {
r.Log.Info("Error creating dynamic client", "error", err)
return
}

resource := schema.GroupVersionResource{
Group: gvk.Group,
Version: gvk.Version,
Resource: "ovirtvolumepopulators", // Use the plural form of the resource
}

unstructuredList, err := dynamicClient.Resource(resource).Namespace(r.Plan.Spec.TargetNamespace).List(context.TODO(), meta.ListOptions{
LabelSelector: labels.SelectorFromSet(map[string]string{"migration": string(r.Plan.Status.Migration.ActiveSnapshot().Migration.UID)}).String(),
})
if err != nil {
r.Log.Info("Error listing OvirtVolumePopulator", "error", err)
return
}

// Convert the unstructured list to the structured list
err = runtime.DefaultUnstructuredConverter.FromUnstructured(unstructuredList.UnstructuredContent(), &populatorCrList)
if err != nil {
r.Log.Info("Error converting unstructured list", "error", err)
return
}

r.Log.Info("Successfully retrieved OvirtVolumePopulator list")
return
}

Expand Down
10 changes: 10 additions & 0 deletions pkg/controller/plan/migration.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ func (r *Migration) deletePopulatorPVCs(vm *plan.VMStatus) (err error) {

// Delete left over migration resources associated with a VM.
func (r *Migration) cleanup(vm *plan.VMStatus, failOnErr func(error) bool) error {
r.Log.Info("Benny cleanup")
if !vm.HasCondition(Succeeded) {
if err := r.kubevirt.DeleteVM(vm); failOnErr(err) {
return err
Expand All @@ -451,12 +452,15 @@ func (r *Migration) cleanup(vm *plan.VMStatus, failOnErr func(error) bool) error
return err
}
}
r.Log.Info("Benny cleanup deleteImporterPods")
if err := r.deleteImporterPods(vm); failOnErr(err) {
return err
}
r.Log.Info("Benny cleanup DeletePVCConsumerPod")
if err := r.kubevirt.DeletePVCConsumerPod(vm); failOnErr(err) {
return err
}

if err := r.kubevirt.DeleteGuestConversionPod(vm); failOnErr(err) {
return err
}
Expand All @@ -470,10 +474,12 @@ func (r *Migration) cleanup(vm *plan.VMStatus, failOnErr func(error) bool) error
return err
}
if r.Plan.Provider.Destination.IsHost() {
r.Log.Info("Benny cleanup DeletePopulatorDataSource")
if err := r.destinationClient.DeletePopulatorDataSource(vm); failOnErr(err) {
return err
}
}
r.Log.Info("Benny cleanup DeletePopulatorPods")
if err := r.kubevirt.DeletePopulatorPods(vm); failOnErr(err) {
return err
}
Expand Down Expand Up @@ -697,6 +703,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) {

switch vm.Phase {
case Started:
r.Log.Info("Benny before Started")
step, found := vm.FindStep(r.step(vm))
if !found {
vm.AddError(fmt.Sprintf("Step '%s' not found", r.step(vm)))
Expand All @@ -712,6 +719,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) {
break
}
vm.Phase = r.next(vm.Phase)
r.Log.Info("Benny after Started")
case PreHook, PostHook:
runner := HookRunner{Context: r.Context}
err = runner.Run(vm)
Expand All @@ -735,6 +743,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) {
}

var ready bool
r.Log.Info("Benny before PreTransferActions")
ready, err = r.provider.PreTransferActions(vm.Ref)
if err != nil {
if !errors.As(err, &web.ProviderNotReadyError{}) {
Expand All @@ -746,6 +755,7 @@ func (r *Migration) execute(vm *plan.VMStatus) (err error) {
}
}

r.Log.Info("Benny before SupportsVolumePopulators")
if r.builder.SupportsVolumePopulators() {
var pvcs []*core.PersistentVolumeClaim
if pvcs, err = r.kubevirt.PopulatorVolumes(vm.Ref); err != nil {
Expand Down

0 comments on commit e0b1d66

Please sign in to comment.