disable block volume data mover on windows

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
Lyndon-Li
2024-11-28 16:02:03 +08:00
parent 03d0bd9d22
commit bc6414672e
5 changed files with 118 additions and 6 deletions

View File

@@ -803,14 +803,18 @@ func (r *DataUploadReconciler) setupExposeParam(du *velerov2alpha1api.DataUpload
return nil, errors.Wrapf(err, "failed to get PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC)
}
nodeOS, err := kube.GetPVCAttachingNodeOS(pvc, r.kubeClient.CoreV1(), r.kubeClient.StorageV1(), r.logger)
accessMode := exposer.AccessModeFileSystem
if pvc.Spec.VolumeMode != nil && *pvc.Spec.VolumeMode == corev1.PersistentVolumeBlock {
accessMode = exposer.AccessModeBlock
}
nodeOS, err := kube.GetPVCAttachingNodeOS(pvc, (accessMode == exposer.AccessModeBlock), r.kubeClient.CoreV1(), r.kubeClient.StorageV1(), r.logger)
if err != nil {
return nil, errors.Wrapf(err, "failed to get attaching node OS for PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC)
}
accessMode := exposer.AccessModeFileSystem
if pvc.Spec.VolumeMode != nil && *pvc.Spec.VolumeMode == corev1.PersistentVolumeBlock {
accessMode = exposer.AccessModeBlock
if err := kube.HasNodeWithOS(context.Background(), nodeOS, r.kubeClient.CoreV1()); err != nil {
return nil, errors.Wrapf(err, "no appropriate node to run data upload for PVC %s/%s", du.Spec.SourceNamespace, du.Spec.SourcePVC)
}
hostingPodLabels := map[string]string{velerov1api.DataUploadLabel: du.Name}

View File

@@ -17,6 +17,7 @@ package kube
import (
"context"
"fmt"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -99,3 +100,20 @@ func GetNodeOS(ctx context.Context, nodeName string, nodeClient corev1client.Cor
return node.Labels[NodeOSLabel], nil
}
func HasNodeWithOS(ctx context.Context, os string, nodeClient corev1client.CoreV1Interface) error {
if os == "" {
return errors.New("invalid node OS")
}
nodes, err := nodeClient.Nodes().List(ctx, metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", NodeOSLabel, os)})
if err != nil {
return errors.Wrapf(err, "error listing nodes with OS %s", os)
}
if len(nodes.Items) == 0 {
return errors.Errorf("node with OS %s doesn't exist", os)
}
return nil
}

View File

@@ -20,6 +20,7 @@ import (
"context"
"testing"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -27,6 +28,7 @@ import (
"github.com/vmware-tanzu/velero/pkg/builder"
kubeClientFake "k8s.io/client-go/kubernetes/fake"
clientTesting "k8s.io/client-go/testing"
clientFake "sigs.k8s.io/controller-runtime/pkg/client/fake"
velerotest "github.com/vmware-tanzu/velero/pkg/test"
@@ -181,3 +183,79 @@ func TestGetNodeOSType(t *testing.T) {
})
}
}
func TestHasNodeWithOS(t *testing.T) {
nodeNoOSLabel := builder.ForNode("fake-node-1").Result()
nodeWindows := builder.ForNode("fake-node-2").Labels(map[string]string{"kubernetes.io/os": "windows"}).Result()
nodeLinux := builder.ForNode("fake-node-3").Labels(map[string]string{"kubernetes.io/os": "linux"}).Result()
scheme := runtime.NewScheme()
corev1.AddToScheme(scheme)
tests := []struct {
name string
kubeClientObj []runtime.Object
kubeReactors []reactor
os string
err string
}{
{
name: "os is empty",
err: "invalid node OS",
},
{
name: "error to list node",
kubeReactors: []reactor{
{
verb: "list",
resource: "nodes",
reactorFunc: func(action clientTesting.Action) (handled bool, ret runtime.Object, err error) {
return true, nil, errors.New("fake-list-error")
},
},
},
os: "linux",
err: "error listing nodes with OS linux: fake-list-error",
},
{
name: "no expected node - no node",
os: "linux",
err: "node with OS linux doesn't exist",
},
{
name: "no expected node - no node with label",
kubeClientObj: []runtime.Object{
nodeNoOSLabel,
nodeWindows,
},
os: "linux",
err: "node with OS linux doesn't exist",
},
{
name: "succeed",
kubeClientObj: []runtime.Object{
nodeNoOSLabel,
nodeWindows,
nodeLinux,
},
os: "windows",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
fakeKubeClient := kubeClientFake.NewSimpleClientset(test.kubeClientObj...)
for _, reactor := range test.kubeReactors {
fakeKubeClient.Fake.PrependReactor(reactor.verb, reactor.resource, reactor.reactorFunc)
}
err := HasNodeWithOS(context.TODO(), test.os, fakeKubeClient.CoreV1())
if test.err != "" {
assert.EqualError(t, err, test.err)
} else {
assert.NoError(t, err)
}
})
}
}

View File

@@ -429,11 +429,16 @@ func DiagnosePV(pv *corev1api.PersistentVolume) string {
return diag
}
func GetPVCAttachingNodeOS(pvc *corev1api.PersistentVolumeClaim, nodeClient corev1client.CoreV1Interface,
func GetPVCAttachingNodeOS(pvc *corev1api.PersistentVolumeClaim, blockAccess bool, nodeClient corev1client.CoreV1Interface,
storageClient storagev1.StorageV1Interface, log logrus.FieldLogger) (string, error) {
var nodeOS string
var scFsType string
if blockAccess {
log.Infof("Use linux node for block access for PVC %s/%s", pvc.Namespace, pvc.Name)
return NodeOSLinux, nil
}
if value := pvc.Annotations[KubeAnnSelectedNode]; value != "" {
os, err := GetNodeOS(context.Background(), value, nodeClient)
if err != nil {

View File

@@ -1610,6 +1610,7 @@ func TestGetPVCAttachingNodeOS(t *testing.T) {
name string
pvc *corev1api.PersistentVolumeClaim
kubeClientObj []runtime.Object
blockAccess bool
expectedNodeOS string
err string
}{
@@ -1662,6 +1663,12 @@ func TestGetPVCAttachingNodeOS(t *testing.T) {
},
expectedNodeOS: NodeOSWindows,
},
{
name: "block access",
pvc: pvcObjWithBoth,
blockAccess: true,
expectedNodeOS: NodeOSLinux,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
@@ -1669,7 +1676,7 @@ func TestGetPVCAttachingNodeOS(t *testing.T) {
var kubeClient kubernetes.Interface = fakeKubeClient
nodeOS, err := GetPVCAttachingNodeOS(test.pvc, kubeClient.CoreV1(), kubeClient.StorageV1(), velerotest.NewLogger())
nodeOS, err := GetPVCAttachingNodeOS(test.pvc, test.blockAccess, kubeClient.CoreV1(), kubeClient.StorageV1(), velerotest.NewLogger())
if err != nil {
assert.EqualError(t, err, test.err)