Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ limitations under the License.
package service

import (
"cmp"
"context"
"errors"
"fmt"
Expand All @@ -43,6 +42,7 @@ import (
"github.com/deckhouse/virtualization-controller/pkg/common/pointer"
"github.com/deckhouse/virtualization-controller/pkg/controller/conditions"
"github.com/deckhouse/virtualization-controller/pkg/controller/kvbuilder"
"github.com/deckhouse/virtualization-controller/pkg/controller/service/volumemode"
"github.com/deckhouse/virtualization-controller/pkg/controller/supplements"
"github.com/deckhouse/virtualization-controller/pkg/dvcr"
"github.com/deckhouse/virtualization/api/core/v1alpha2"
Expand All @@ -53,6 +53,8 @@ type DiskService struct {
dvcrSettings *dvcr.Settings
protection *ProtectionService
controllerName string

volumeAndAccessModesGetter volumemode.VolumeAndAccessModesGetter
}

func NewDiskService(
Expand All @@ -62,10 +64,11 @@ func NewDiskService(
controllerName string,
) *DiskService {
return &DiskService{
client: client,
dvcrSettings: dvcrSettings,
protection: protection,
controllerName: controllerName,
client: client,
dvcrSettings: dvcrSettings,
protection: protection,
controllerName: controllerName,
volumeAndAccessModesGetter: volumemode.NewVolumeAndAccessModesGetter(client, nil),
}
}

Expand Down Expand Up @@ -125,54 +128,7 @@ func (s DiskService) Start(
}

func (s DiskService) GetVolumeAndAccessModes(ctx context.Context, obj client.Object, sc *storagev1.StorageClass) (corev1.PersistentVolumeMode, corev1.PersistentVolumeAccessMode, error) {
if obj == nil {
return "", "", errors.New("object is nil")
}
if sc == nil {
return "", "", errors.New("storage class is nil")
}

// Priority: object > storage class > storage profile.

// 1. Get modes from annotations on the object.
accessMode, _ := s.parseAccessMode(obj)
volumeMode, _ := s.parseVolumeMode(obj)

if accessMode != "" && volumeMode != "" {
return volumeMode, accessMode, nil
}

// 2. Get modes from annotations on the storage class.
if m, exists := s.parseAccessMode(sc); accessMode == "" && exists {
accessMode = m
}
if m, exists := s.parseVolumeMode(sc); volumeMode == "" && exists {
volumeMode = m
}

if accessMode != "" && volumeMode != "" {
return volumeMode, accessMode, nil
}

// 3. Get modes from storage profile.
storageProfile, err := s.GetStorageProfile(ctx, sc.Name)
if err != nil {
return "", "", fmt.Errorf("get storage profile: %w", err)
}

if storageProfile == nil {
return "", "", fmt.Errorf("storage profile %q not found: %w", sc.Name, ErrStorageProfileNotFound)
}

storageCaps := s.parseStorageCapabilities(storageProfile.Status)
if accessMode == "" && storageCaps.AccessMode != "" {
accessMode = storageCaps.AccessMode
}
if volumeMode == "" && storageCaps.VolumeMode != "" {
volumeMode = storageCaps.VolumeMode
}

return volumeMode, accessMode, nil
return s.volumeAndAccessModesGetter.GetVolumeAndAccessModes(ctx, obj, sc)
}

func (s DiskService) StartImmediate(
Expand Down Expand Up @@ -446,105 +402,13 @@ func (s DiskService) GetStorageProfile(ctx context.Context, name string) (*cdiv1
return object.FetchObject(ctx, types.NamespacedName{Name: name}, s.client, &cdiv1.StorageProfile{})
}

type StorageCapabilities struct {
AccessMode corev1.PersistentVolumeAccessMode
VolumeMode corev1.PersistentVolumeMode
}

func (cp StorageCapabilities) IsEmpty() bool {
return cp.AccessMode == "" && cp.VolumeMode == ""
}

var accessModeWeights = map[corev1.PersistentVolumeAccessMode]int{
corev1.ReadOnlyMany: 0,
corev1.ReadWriteOncePod: 1,
corev1.ReadWriteOnce: 2,
corev1.ReadWriteMany: 3,
}

var volumeModeWeights = map[corev1.PersistentVolumeMode]int{
corev1.PersistentVolumeFilesystem: 0,
corev1.PersistentVolumeBlock: 1,
}

func getAccessModeMax(modes []corev1.PersistentVolumeAccessMode) corev1.PersistentVolumeAccessMode {
weight := -1
var m corev1.PersistentVolumeAccessMode
for _, mode := range modes {
if accessModeWeights[mode] > weight {
weight = accessModeWeights[mode]
m = mode
}
}
return m
}

func (s DiskService) parseVolumeMode(obj client.Object) (corev1.PersistentVolumeMode, bool) {
if obj == nil {
return "", false
}
switch obj.GetAnnotations()[annotations.AnnVirtualDiskVolumeMode] {
case string(corev1.PersistentVolumeBlock):
return corev1.PersistentVolumeBlock, true
case string(corev1.PersistentVolumeFilesystem):
return corev1.PersistentVolumeFilesystem, true
default:
return "", false
}
}

func (s DiskService) parseAccessMode(obj client.Object) (corev1.PersistentVolumeAccessMode, bool) {
if obj == nil {
return "", false
}
switch obj.GetAnnotations()[annotations.AnnVirtualDiskAccessMode] {
case string(corev1.ReadWriteOnce):
return corev1.ReadWriteOnce, true
case string(corev1.ReadWriteMany):
return corev1.ReadWriteMany, true
default:
return "", false
}
}

func (s DiskService) isImmediateBindingMode(sc *storagev1.StorageClass) bool {
if sc == nil {
return false
}
return sc.GetAnnotations()[annotations.AnnVirtualDiskBindingMode] == string(storagev1.VolumeBindingImmediate)
}

func (s DiskService) parseStorageCapabilities(status cdiv1.StorageProfileStatus) StorageCapabilities {
var storageCapabilities []StorageCapabilities
for _, cp := range status.ClaimPropertySets {
var mode corev1.PersistentVolumeMode
if cp.VolumeMode == nil || *cp.VolumeMode == "" {
mode = corev1.PersistentVolumeFilesystem
} else {
mode = *cp.VolumeMode
}
storageCapabilities = append(storageCapabilities, StorageCapabilities{
AccessMode: getAccessModeMax(cp.AccessModes),
VolumeMode: mode,
})
}
slices.SortFunc(storageCapabilities, func(a, b StorageCapabilities) int {
if c := cmp.Compare(accessModeWeights[a.AccessMode], accessModeWeights[b.AccessMode]); c != 0 {
return c
}
return cmp.Compare(volumeModeWeights[a.VolumeMode], volumeModeWeights[b.VolumeMode])
})

if len(storageCapabilities) == 0 {
return StorageCapabilities{
AccessMode: corev1.ReadWriteOnce,
VolumeMode: corev1.PersistentVolumeFilesystem,
}
}

return storageCapabilities[len(storageCapabilities)-1]
}

func (s DiskService) GetStorageClass(ctx context.Context, scName string) (*storagev1.StorageClass, error) {
return object.FetchObject(ctx, types.NamespacedName{Name: scName}, s.client, &storagev1.StorageClass{})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
)

var (
ErrStorageProfileNotFound = errors.New("storage profile not found")
ErrDefaultStorageClassNotFound = errors.New("default storage class not found")
ErrDataVolumeNotRunning = errors.New("pvc importer is not running")
ErrDataVolumeProvisionerUnschedulable = errors.New("provisioner unschedulable")
Expand Down
Loading
Loading