Skip to content

Add support of direct FC storage from oVirt #657

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pkg/controller/plan/adapter/base/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ type Client interface {
type Validator interface {
// Validate that a VM's disk backing storage has been mapped.
StorageMapped(vmRef ref.Ref) (bool, error)
// Validate that a VM's direct LUN/FC has the required details (oVirt only)
DirectStorage(vmRef ref.Ref) (bool, error)
// Validate that a VM's networks have been mapped.
NetworksMapped(vmRef ref.Ref) (bool, error)
// Validate that a VM's Host isn't in maintenance mode.
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/plan/adapter/ocp/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,3 +179,8 @@ func (r *Validator) NetworksMapped(vmRef ref.Ref) (ok bool, err error) {

return true, nil
}

// NO-OP
func (r *Validator) DirectStorage(vmRef ref.Ref) (bool, error) {
return true, nil
}
5 changes: 5 additions & 0 deletions pkg/controller/plan/adapter/openstack/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,8 @@ func (r *Validator) PodNetwork(vmRef ref.Ref) (ok bool, err error) {
ok = podMapped <= 1
return
}

// NO-OP
func (r *Validator) DirectStorage(vmRef ref.Ref) (bool, error) {
return true, nil
}
5 changes: 5 additions & 0 deletions pkg/controller/plan/adapter/ova/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,3 +108,8 @@ func (r *Validator) MaintenanceMode(vmRef ref.Ref) (ok bool, err error) {
ok = true
return
}

// NO-OP
func (r *Validator) DirectStorage(vmRef ref.Ref) (bool, error) {
return true, nil
}
1 change: 1 addition & 0 deletions pkg/controller/plan/adapter/ovirt/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ go_library(
"//pkg/controller/plan/adapter/base",
"//pkg/controller/plan/context",
"//pkg/controller/plan/util",
"//pkg/controller/provider/container",
"//pkg/controller/provider/container/ovirt",
"//pkg/controller/provider/web",
"//pkg/controller/provider/web/base",
Expand Down
28 changes: 20 additions & 8 deletions pkg/controller/plan/adapter/ovirt/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -576,6 +576,25 @@ func (r *Builder) LunPersistentVolumes(vmRef ref.Ref) (pvs []core.PersistentVolu
volMode := core.PersistentVolumeBlock
logicalUnit := da.Disk.Lun.LogicalUnits.LogicalUnit[0]

var pvSource core.PersistentVolumeSource
if logicalUnit.Address != "" {
pvSource = core.PersistentVolumeSource{
ISCSI: &core.ISCSIPersistentVolumeSource{
TargetPortal: logicalUnit.Address + ":" + logicalUnit.Port,
IQN: logicalUnit.Target,
Lun: logicalUnit.LunMapping,
ReadOnly: false,
},
}
} else {
pvSource = core.PersistentVolumeSource{
FC: &core.FCVolumeSource{
WWIDs: []string{logicalUnit.LunID},
ReadOnly: false,
},
}
}

pvSpec := core.PersistentVolume{
ObjectMeta: meta.ObjectMeta{
Name: da.Disk.ID,
Expand All @@ -591,14 +610,7 @@ func (r *Builder) LunPersistentVolumes(vmRef ref.Ref) (pvs []core.PersistentVolu
},
},
Spec: core.PersistentVolumeSpec{
PersistentVolumeSource: core.PersistentVolumeSource{
ISCSI: &core.ISCSIPersistentVolumeSource{
TargetPortal: logicalUnit.Address + ":" + logicalUnit.Port,
IQN: logicalUnit.Target,
Lun: logicalUnit.LunMapping,
ReadOnly: false,
},
},
PersistentVolumeSource: pvSource,
Capacity: core.ResourceList{
core.ResourceStorage: *resource.NewQuantity(logicalUnit.Size, resource.BinarySI),
},
Expand Down
1 change: 1 addition & 0 deletions pkg/controller/plan/adapter/ovirt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ func (r *Client) getVM(vmRef ref.Ref) (ovirtVm *ovirtsdk.Vm, vmService *ovirtsdk
vmRef.String())
return
}

vmService = r.connection.SystemService().VmsService().VmService(vm.ID)
vmResponse, err := vmService.Get().Query("correlation_id", r.Migration.Name).Send()
if err != nil {
Expand Down
71 changes: 64 additions & 7 deletions pkg/controller/plan/adapter/ovirt/validator.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package ovirt

import (
"strconv"

api "github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1"
"github.com/konveyor/forklift-controller/pkg/apis/forklift/v1beta1/ref"
"github.com/konveyor/forklift-controller/pkg/controller/provider/container"
"github.com/konveyor/forklift-controller/pkg/controller/provider/web"
model "github.com/konveyor/forklift-controller/pkg/controller/provider/web/ovirt"
liberr "github.com/konveyor/forklift-controller/pkg/lib/error"
"github.com/konveyor/forklift-controller/pkg/settings"
)

// vSphere validator.
// oVirt validator.
type Validator struct {
plan *api.Plan
inventory web.Client
Expand Down Expand Up @@ -105,20 +108,74 @@ func (r *Validator) StorageMapped(vmRef ref.Ref) (ok bool, err error) {
vmRef.String())
return
}

for _, da := range vm.DiskAttachments {
if da.Disk.StorageType != "lun" {
if !r.plan.Referenced.Map.Storage.Status.Refs.Find(ref.Ref{ID: da.Disk.StorageDomain}) {
return
}
} else if len(da.Disk.Lun.LogicalUnits.LogicalUnit) > 0 && da.Disk.Lun.LogicalUnits.LogicalUnit[0].Address == "" {
// Have LUN disk but without the relevant data. This might happen with older oVirt versions.
if da.Disk.StorageType != "lun" && !r.plan.Referenced.Map.Storage.Status.Refs.Find(ref.Ref{ID: da.Disk.StorageDomain}) {
return
}
}
ok = true
return
}

// Validates oVirt version in case we use direct LUN/FC storage
func (r *Validator) DirectStorage(vmRef ref.Ref) (ok bool, err error) {
vm := &model.Workload{}
err = r.inventory.Find(vm, vmRef)
if err != nil {
err = liberr.Wrap(
err,
"VM not found in inventory.",
"vm",
vmRef.String())
return
}

for _, da := range vm.DiskAttachments {
if da.Disk.StorageType == "lun" {
if len(da.Disk.Lun.LogicalUnits.LogicalUnit) > 0 {
if ok, err := r.canImportDirectDisksFromProvider(); !ok {
return ok, err
}
}
}
}
ok = true
return
}

// Checks the version for ovirt direct LUN/FC
func (r *Validator) canImportDirectDisksFromProvider() (bool, error) {
// validate ovirt version > ovirt-engine-4.5.2.1 (https://github.com/oVirt/ovirt-engine/commit/e7c1f585863a332bcecfc8c3d909c9a3a56eb922)
rl := container.Build(nil, r.plan.Referenced.Provider.Source, r.plan.Referenced.Secret)
major, minor, build, revision, err := rl.Version()
if err != nil {
return false, err
}
majorVal, err := strconv.Atoi(major)
if err != nil {
return false, err
}
minorVal, err := strconv.Atoi(minor)
if err != nil {
return false, err
}
buildVal, err := strconv.Atoi(build)
if err != nil {
return false, err
}
revisionVal, err := strconv.Atoi(revision)
if err != nil {
return false, err
}

currentVersion := majorVal*1000 + minorVal*100 + buildVal*10 + revisionVal

const minVersion = 4521

return currentVersion >= minVersion, nil
}

// Validate that a VM's Host isn't in maintenance mode. No-op for oVirt.
func (r *Validator) MaintenanceMode(_ ref.Ref) (ok bool, err error) {
ok = true
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/plan/adapter/vsphere/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,8 @@ func (r *Validator) MaintenanceMode(vmRef ref.Ref) (ok bool, err error) {
ok = !host.InMaintenanceMode
return
}

// NO-OP
func (r *Validator) DirectStorage(vmRef ref.Ref) (bool, error) {
return true, nil
}
40 changes: 40 additions & 0 deletions pkg/controller/plan/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
libcnd "github.com/konveyor/forklift-controller/pkg/lib/condition"
liberr "github.com/konveyor/forklift-controller/pkg/lib/error"
libref "github.com/konveyor/forklift-controller/pkg/lib/ref"
v1 "k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
k8svalidation "k8s.io/apimachinery/pkg/util/validation"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand All @@ -34,6 +35,7 @@ const (
VMAlreadyExists = "VMAlreadyExists"
VMNetworksNotMapped = "VMNetworksNotMapped"
VMStorageNotMapped = "VMStorageNotMapped"
VMStorageNotSupported = "VMStorageNotSupported"
VMMultiplePodNetworkMappings = "VMMultiplePodNetworkMappings"
HostNotReady = "HostNotReady"
DuplicateVM = "DuplicateVM"
Expand Down Expand Up @@ -342,6 +344,14 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
Message: "VM has unmapped storage.",
Items: []string{},
}
unsupportedStorage := libcnd.Condition{
Type: VMStorageNotSupported,
Status: True,
Reason: NotValid,
Category: Critical,
Message: "VM has unsupported storage. Migration of Direct LUN/FC from oVirt is supported as from version 4.5.2.1",
Items: []string{},
}
maintenanceMode := libcnd.Condition{
Type: HostNotReady,
Status: True,
Expand Down Expand Up @@ -411,6 +421,12 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
if err != nil {
return err
}
if plan.Referenced.Secret == nil {
err = r.setupSecret(plan)
if err != nil {
return err
}
}
if plan.Referenced.Map.Network != nil {
ok, err := validator.NetworksMapped(*ref)
if err != nil {
Expand All @@ -435,6 +451,13 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
if !ok {
unmappedStorage.Items = append(unmappedStorage.Items, ref.String())
}
ok, err = validator.DirectStorage(*ref)
if err != nil {
return err
}
if !ok {
unsupportedStorage.Items = append(unsupportedStorage.Items, ref.String())
}
}
ok, err := validator.MaintenanceMode(*ref)
if err != nil {
Expand Down Expand Up @@ -491,6 +514,9 @@ func (r *Reconciler) validateVM(plan *api.Plan) error {
if len(unmappedStorage.Items) > 0 {
plan.Status.SetCondition(unmappedStorage)
}
if len(unsupportedStorage.Items) > 0 {
plan.Status.SetCondition(unsupportedStorage)
}
if len(maintenanceMode.Items) > 0 {
plan.Status.SetCondition(maintenanceMode)
}
Expand Down Expand Up @@ -670,3 +696,17 @@ func (r *Reconciler) validateVddkImage(plan *api.Plan) (err error) {
}
return nil
}

func (r *Reconciler) setupSecret(plan *api.Plan) (err error) {
key := client.ObjectKey{
Namespace: plan.Referenced.Provider.Source.Spec.Secret.Namespace,
Name: plan.Referenced.Provider.Source.Spec.Secret.Name,
}
secret := v1.Secret{}
err = r.Get(context.TODO(), key, &secret)
if err != nil {
return
}
plan.Referenced.Secret = &secret
return
}
5 changes: 5 additions & 0 deletions pkg/controller/provider/container/ocp/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ func New(db libmodel.DB, provider *api.Provider, secret *core.Secret) libcontain
}
}

// NO-OP
func (r *Collector) Version() (_, _, _, _ string, err error) {
return
}

// OCP collector.
type Collector struct {
*libocp.Collector
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/provider/container/openstack/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@ func (r *Collector) Test() (_ int, err error) {
return
}

// NO-OP
func (r *Collector) Version() (_, _, _, _ string, err error) {
return
}

// Start the collector.
func (r *Collector) Start() error {
ctx := Context{
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/provider/container/ova/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ func (r *Collector) Test() (_ int, err error) {
return
}

// NO-OP
func (r *Collector) Version() (_, _, _, _ string, err error) {
return
}

// Start the collector.
func (r *Collector) Start() error {
ctx := Context{
Expand Down
4 changes: 2 additions & 2 deletions pkg/controller/provider/container/ovirt/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,12 +189,12 @@ func (r *Client) get(path string, object interface{}, param ...libweb.Param) (er
}

// Get system.
func (r *Client) system() (s *System, status int, err error) {
func (r *Client) system() (system *System, status int, err error) {
status, err = r.connect()
if err != nil {
return
}
system := &System{}
system = &System{}
status, err = r.client.Get(r.url, system)
if err != nil {
return
Expand Down
16 changes: 16 additions & 0 deletions pkg/controller/provider/container/ovirt/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,22 @@ func (r *Collector) Test() (status int, err error) {
return
}

func (r *Collector) Version() (major, minor, build, revision string, err error) {
system, _, err := r.client.system()
if err != nil {
return
}
version := strings.Split(system.Product.Version.FullVersion, ".")
major = version[0]
minor = version[1]
build = version[2]
revision = "0"
if len(version) > 3 {
revision = strings.Split(version[3], "-")[0]
}
return
}

// Start the collector.
func (r *Collector) Start() error {
ctx := Context{
Expand Down
6 changes: 2 additions & 4 deletions pkg/controller/provider/container/ovirt/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ type System struct {
Name string `json:"name"`
Vendor string `json:"vendor"`
Version struct {
Build string `json:"build"`
Major string `json:"major"`
Minor string `json:"minor"`
Revision string `json:"revision"`
FullVersion string `json:"full_version"`
} `json:"version"`
} `json:"product_info"`
}
Expand Down Expand Up @@ -701,6 +698,7 @@ func (r *Disk) setLun(m *model.Disk) {
}

func (r *LogicalUnit) ApplyTo(m *model.LogicalUnit) {
m.LunID = r.ID
m.Address = r.Address
m.Port = r.Port
m.Target = r.Target
Expand Down
5 changes: 5 additions & 0 deletions pkg/controller/provider/container/vsphere/collector.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,11 @@ func (r *Collector) Test() (status int, err error) {
return
}

// NO-OP
func (r *Collector) Version() (_, _, _, _ string, err error) {
return
}

// Start the collector.
func (r *Collector) Start() error {
ctx := context.Background()
Expand Down
Loading