Repository: kubermatic/machine-controller
Pull request #1872 (2024-10-21 18:47:34)

Refactor kubervirt provider storage
**What this PR does / why we need it**:
This PR set the default kuebvirt storage target from PVC to Storage in order to leverage multiple CSI drivers in the infra cluster instead if using k8s PVC setting which might lead to different issues, such as access mode, volume binding mode, etc... In addition to that, it can read and set the volume access mode to the data volume spec based on the CDI storage profile. 
**Which issue(s) this PR fixes**:
<!--optional, in `fixes #<issue number>` format, will close the issue(s) when PR gets merged-->
Fixes #

**What type of PR is this?**
/kind feature
<!--
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind design

Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
/kind chore
-->

**Special notes for your reviewer**:
Tested manually and worked as expected.

**Does this PR introduce a user-facing change? Then add your Release Note here**:
<!--
Write your release note:
1. Enter your extended release note in the below block. If the PR requires additional action from users switching to the new release, include the string "action required".
2. If no release note is required, just write "NONE".
-->
```release-note
Support `dataVolumeTemplateSpec.dataVolumeSpec.Storage` and configure DataVolume based onn CDI StorageProfile
```

**Documentation**:
<!--
Please do one of the following options:
- Add a link to the existing documentation
- Add a link to the kubermatic/docs pull request
- If no documentation change is applicable then add:
  - TBD (documentation will be added later)
  - NONE (no documentation needed for this PR)
-->
```documentation
None
```


kubermatic-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
**Once this PR has been reviewed and has the lgtm label**, please ask for approval from [moadqassem](https://github.com/moadqassem). For more information see [the Kubernetes Code Review Process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process).

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubermatic%2Fmachine-controller).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/kubermatic/machine-controller/blob/main/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["moadqassem"]} -->
kubermatic-bot: @moadqassem: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-machine-controller-lint | 2012c08513e08b77919db3eecc74abb1b12983de | [link](https://public-prow.loodse.com/view/gs/prow-dev-public-data/pr-logs/pull/kubermatic_machine-controller/1872/pull-machine-controller-lint/1848435995003850752) | true | `/test pull-machine-controller-lint`

[Full PR test history](https://public-prow.loodse.com/pr-history?org=kubermatic&repo=machine-controller&pr=1872)

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [kubernetes-sigs/prow](https://github.com/kubernetes-sigs/prow/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
yaa110: /approve
/lgtm
kubermatic-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/kubermatic/machine-controller/pull/1872#issuecomment-2428403906" title="LGTM">yaa110</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=kubermatic%2Fmachine-controller).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/kubermatic/machine-controller/blob/main/OWNERS)~~ [yaa110]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
kubermatic-bot: LGTM label has been added.  <details>Git tree hash: 7a089e7eb59cf01d3dc6408618ee6716e8602295</details>

Patch:
diff --git a/pkg/cloudprovider/provider/kubevirt/provider.go b/pkg/cloudprovider/provider/kubevirt/provider.go
index c08eb189..723cbef5 100644
--- a/pkg/cloudprovider/provider/kubevirt/provider.go
+++ b/pkg/cloudprovider/provider/kubevirt/provider.go
@@ -124,6 +124,7 @@ type StorageTarget string
 
 const (
 	Storage StorageTarget = "storage"
+	PVC     StorageTarget = "pvc"
 )
 
 type AffinityType string
@@ -308,30 +309,14 @@ func (p *provider) getConfig(provSpec clusterv1alpha1.ProviderSpec) (*Config, *p
 	if rawConfig.VirtualMachine.DNSConfig != nil {
 		config.DNSConfig = rawConfig.VirtualMachine.DNSConfig
 	}
-	config.SecondaryDisks = make([]SecondaryDisks, 0, len(rawConfig.VirtualMachine.Template.SecondaryDisks))
-	for i, sd := range rawConfig.VirtualMachine.Template.SecondaryDisks {
-		sdSizeString, err := p.configVarResolver.GetConfigVarStringValue(sd.Size)
-		if err != nil {
-			return nil, nil, fmt.Errorf(`failed to parse "secondaryDisks.size" field: %w`, err)
-		}
-		pvc, err := resource.ParseQuantity(sdSizeString)
-		if err != nil {
-			return nil, nil, fmt.Errorf(`failed to parse value of "secondaryDisks.size" field: %w`, err)
-		}
-
-		scString, err := p.configVarResolver.GetConfigVarStringValue(sd.StorageClassName)
-		if err != nil {
-			return nil, nil, fmt.Errorf(`failed to parse value of "secondaryDisks.storageClass" field: %w`, err)
-		}
-		config.SecondaryDisks = append(config.SecondaryDisks, SecondaryDisks{
-			Name:              fmt.Sprintf("secondarydisk%d", i),
-			Size:              pvc,
-			StorageClassName:  scString,
-			StorageAccessType: p.getStorageAccessType(sd.StorageAccessType),
-		})
+	infraClient, err := client.New(config.RestConfig, client.Options{})
+	if err != nil {
+		return nil, nil, fmt.Errorf("failed to get kubevirt client: %w", err)
+	}
+	config.StorageAccessType, config.SecondaryDisks, err = p.configureStorage(infraClient, rawConfig.VirtualMachine.Template)
+	if err != nil {
+		return nil, nil, fmt.Errorf(`failed to configure storage: %w`, err)
 	}
-	config.StorageAccessType = p.getStorageAccessType(rawConfig.VirtualMachine.Template.PrimaryDisk.StorageAccessType)
-
 	config.NodeAffinityPreset, err = p.parseNodeAffinityPreset(rawConfig.Affinity.NodeAffinityPreset)
 	if err != nil {
 		return nil, nil, fmt.Errorf(`failed to parse "nodeAffinityPreset" field: %w`, err)
@@ -356,12 +341,29 @@ func (p *provider) getConfig(provSpec clusterv1alpha1.ProviderSpec) (*Config, *p
 	return &config, pconfig, nil
 }
 
-func (p *provider) getStorageAccessType(accessType providerconfigtypes.ConfigVarString) corev1.PersistentVolumeAccessMode {
+func (p *provider) getStorageAccessType(ctx context.Context, accessType providerconfigtypes.ConfigVarString,
+	infraClient client.Client, storageClassName string) (corev1.PersistentVolumeAccessMode, error) {
 	at, _ := p.configVarResolver.GetConfigVarStringValue(accessType)
 	if at == "" {
-		return corev1.ReadWriteOnce
+		sp := &cdiv1beta1.StorageProfile{}
+		if err := infraClient.Get(ctx, types.NamespacedName{Name: storageClassName}, sp); err != nil {
+			return "", fmt.Errorf(`failed to get cdi storageprofile: %w`, err)
+		}
+
+		// choose RWO as a default access mode and if RWX is supported then choose it instead.
+		accessMode := corev1.ReadWriteOnce
+		for _, claimProperty := range sp.Status.ClaimPropertySets {
+			for _, am := range claimProperty.AccessModes {
+				if am == corev1.ReadWriteMany {
+					accessMode = corev1.ReadWriteMany
+				}
+			}
+		}
+
+		return accessMode, nil
 	}
-	return corev1.PersistentVolumeAccessMode(at)
+
+	return corev1.PersistentVolumeAccessMode(at), nil
 }
 
 func (p *provider) parseNodeAffinityPreset(nodeAffinityPreset kubevirttypes.NodeAffinityPreset) (NodeAffinityPreset, error) {
@@ -712,7 +714,13 @@ func (p *provider) newVirtualMachine(c *Config, pc *providerconfigtypes.Config,
 	}
 
 	defaultBridgeNetwork := defaultBridgeNetwork()
-	runStrategyOnce := kubevirtv1.RunStrategyOnce
+	runStrategy := kubevirtv1.RunStrategyOnce
+	// currently we only support KubeOvn as a ProviderNetwork and KubeOvn has the ability to pin the IP of the VM(static ip)
+	// even if the VMi was stopped or deleted thus we can have the VM always running and in the events of VM restarts the
+	// ip address of the VMI will not change.
+	if c.SubnetName != "" {
+		runStrategy = kubevirtv1.RunStrategyAlways
+	}
 
 	virtualMachine := &kubevirtv1.VirtualMachine{
 		ObjectMeta: metav1.ObjectMeta{
@@ -721,7 +729,7 @@ func (p *provider) newVirtualMachine(c *Config, pc *providerconfigtypes.Config,
 			Labels:    labels,
 		},
 		Spec: kubevirtv1.VirtualMachineSpec{
-			RunStrategy:  &runStrategyOnce,
+			RunStrategy:  &runStrategy,
 			Instancetype: c.Instancetype,
 			Preference:   c.Preference,
 			Template: &kubevirtv1.VirtualMachineInstanceTemplateSpec{
@@ -885,8 +893,8 @@ func getDataVolumeTemplates(config *Config, dataVolumeName string, annotations m
 	}
 
 	switch config.StorageTarget {
-	case Storage:
-		dataVolumeTemplates[0].Spec.Storage = &cdiv1beta1.StorageSpec{
+	case PVC:
+		dataVolumeTemplates[0].Spec.PVC = &corev1.PersistentVolumeClaimSpec{
 			StorageClassName: ptr.To(config.StorageClassName),
 			AccessModes: []corev1.PersistentVolumeAccessMode{
 				config.StorageAccessType,
@@ -896,7 +904,7 @@ func getDataVolumeTemplates(config *Config, dataVolumeName string, annotations m
 			},
 		}
 	default:
-		dataVolumeTemplates[0].Spec.PVC = &corev1.PersistentVolumeClaimSpec{
+		dataVolumeTemplates[0].Spec.Storage = &cdiv1beta1.StorageSpec{
 			StorageClassName: ptr.To(config.StorageClassName),
 			AccessModes: []corev1.PersistentVolumeAccessMode{
 				config.StorageAccessType,
@@ -1064,3 +1072,44 @@ func setOVNAnnotations(c *Config, annotations map[string]string) error {
 
 	return nil
 }
+
+func (p *provider) configureStorage(infraClient client.Client, template kubevirttypes.Template) (corev1.PersistentVolumeAccessMode, []SecondaryDisks, error) {
+	secondaryDisks := make([]SecondaryDisks, 0, len(template.SecondaryDisks))
+	for i, sd := range template.SecondaryDisks {
+		sdSizeString, err := p.configVarResolver.GetConfigVarStringValue(sd.Size)
+		if err != nil {
+			return "", nil, fmt.Errorf(`failed to parse "secondaryDisks.size" field: %w`, err)
+		}
+		pvc, err := resource.ParseQuantity(sdSizeString)
+		if err != nil {
+			return "", nil, fmt.Errorf(`failed to parse value of "secondaryDisks.size" field: %w`, err)
+		}
+
+		scString, err := p.configVarResolver.GetConfigVarStringValue(sd.StorageClassName)
+		if err != nil {
+			return "", nil, fmt.Errorf(`failed to parse value of "secondaryDisks.storageClass" field: %w`, err)
+		}
+		storageAccessMode, err := p.getStorageAccessType(context.TODO(), sd.StorageAccessType, infraClient, scString)
+		if err != nil {
+			return "", nil, fmt.Errorf(`failed to get value of storageAccessMode: %w`, err)
+		}
+		secondaryDisks = append(secondaryDisks, SecondaryDisks{
+			Name:              fmt.Sprintf("secondarydisk%d", i),
+			Size:              pvc,
+			StorageClassName:  scString,
+			StorageAccessType: storageAccessMode,
+		})
+	}
+	scString, err := p.configVarResolver.GetConfigVarStringValue(template.PrimaryDisk.StorageClassName)
+	if err != nil {
+		return "", nil, fmt.Errorf(`failed to parse value of "primaryDisk.storageClass" field: %w`, err)
+	}
+
+	primaryDisk, err := p.getStorageAccessType(context.TODO(), template.PrimaryDisk.StorageAccessType,
+		infraClient, scString)
+	if err != nil {
+		return "", nil, fmt.Errorf(`failed to get value of primaryDiskstorageAccessType: %w`, err)
+	}
+
+	return primaryDisk, secondaryDisks, nil
+}


Test patch:
diff --git a/pkg/cloudprovider/provider/kubevirt/provider_test.go b/pkg/cloudprovider/provider/kubevirt/provider_test.go
index 991d5f13..c5841214 100644
--- a/pkg/cloudprovider/provider/kubevirt/provider_test.go
+++ b/pkg/cloudprovider/provider/kubevirt/provider_test.go
@@ -132,11 +132,14 @@ func (k kubevirtProviderSpecConf) rawProviderSpec(t *testing.T) []byte {
 				{{- if .SecondaryDisks }}
 				"secondaryDisks": [{
 					"size": "20Gi",
+                    "storageAccessType": "ReadWriteMany",
 					"storageClassName": "longhorn2"},{
 					"size": "30Gi",
+                    "storageAccessType": "ReadWriteMany",
 					"storageClassName": "longhorn3"}],
 				{{- end }}
 				"primaryDisk": {
+                    "storageAccessType": "ReadWriteMany",
 					{{- if .StorageTarget }}
 					"storageTarget": "{{ .StorageTarget }}",
 					{{- end }}
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/affinity-no-values.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/affinity-no-values.yaml
index 48dbb7d0..a8382d8e 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/affinity-no-values.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/affinity-no-values.yaml
@@ -15,9 +15,9 @@ spec:
         creationTimestamp: null
         name: affinity-no-values
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/affinity.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/affinity.yaml
index 2460731d..7c0a3e9d 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/affinity.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/affinity.yaml
@@ -15,9 +15,9 @@ spec:
         creationTimestamp: null
         name: affinity
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/custom-local-disk.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/custom-local-disk.yaml
index 32d50db2..b83d4b01 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/custom-local-disk.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/custom-local-disk.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: custom-local-disk
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/http-image-source.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/http-image-source.yaml
index 289549ed..f36d5392 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/http-image-source.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/http-image-source.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: http-image-source
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-custom.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-custom.yaml
index 6df4ec46..9154f71c 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-custom.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-custom.yaml
@@ -15,9 +15,9 @@ spec:
         creationTimestamp: null
         name: instancetype-preference-custom
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-standard.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-standard.yaml
index 12f591b5..c890481c 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-standard.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/instancetype-preference-standard.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: instancetype-preference-standard
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/kubeovn-provider-network.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/kubeovn-provider-network.yaml
index 9f0f8948..aa8dc5b6 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/kubeovn-provider-network.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/kubeovn-provider-network.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: kubeovn-provider-network
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
@@ -24,7 +24,7 @@ spec:
         source:
           http:
             url: http://x.y.z.t/ubuntu.img
-  runStrategy: Once
+  runStrategy: Always
   template:
     metadata:
       creationTimestamp: null
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/nominal-case.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/nominal-case.yaml
index 81651774..58f1ae77 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/nominal-case.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/nominal-case.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: nominal-case
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/pvc-image-source.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/pvc-image-source.yaml
index 07159c1a..61884708 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/pvc-image-source.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/pvc-image-source.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: pvc-image-source
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source-pod.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source-pod.yaml
index 5e197b77..69aaaac7 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source-pod.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source-pod.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: registry-image-source-pod
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source.yaml
index 7ea3bdfd..f4608a12 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/registry-image-source.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: registry-image-source
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/secondary-disks.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/secondary-disks.yaml
index 2976b746..8abda0e5 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/secondary-disks.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/secondary-disks.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: secondary-disks
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
@@ -29,7 +29,7 @@ spec:
       spec:
         pvc:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 20Gi
@@ -42,7 +42,7 @@ spec:
       spec:
         pvc:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 30Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/topologyspreadconstraints.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/topologyspreadconstraints.yaml
index 71828981..14109166 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/topologyspreadconstraints.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/topologyspreadconstraints.yaml
@@ -14,9 +14,9 @@ spec:
     - metadata:
         name: topologyspreadconstraints
       spec:
-        pvc:
+        storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi
diff --git a/pkg/cloudprovider/provider/kubevirt/testdata/use-storage-as-storage-target.yaml b/pkg/cloudprovider/provider/kubevirt/testdata/use-storage-as-storage-target.yaml
index 813faf8f..b441d553 100644
--- a/pkg/cloudprovider/provider/kubevirt/testdata/use-storage-as-storage-target.yaml
+++ b/pkg/cloudprovider/provider/kubevirt/testdata/use-storage-as-storage-target.yaml
@@ -20,7 +20,7 @@ spec:
             url: "http://x.y.z.t/ubuntu.img"
         storage:
           accessModes:
-            - ReadWriteOnce
+            - ReadWriteMany
           resources:
             requests:
               storage: 10Gi