Repository: openshift/hypershift-oadp-plugin
Pull request #18: CNTRLPLANE-362: HCP-OADP Plugin: Add support for Kubevirt Platform
Author: login: LiangquanLi930
Labels: name: lgtm
description: Indicates that a PR is ready to be merged.
name: jira/valid-reference
description: Indicates that this PR references a valid Jira ticket of any type.
name: approved
description: Indicates a PR has been approved by an approver from all required OWNERS files.
Created: 2025-04-23T06:09:44Z | Merged: 2025-04-29T06:53:32Z

## What this PR does / why we need it
Add support for Kubevirt Platform
Reference doc: https://docs.google.com/document/d/1MsqSi-fAaJD7s1Kee1ty83DsfNBasneq2Slw8Xc9imE/edit?tab=t.0#heading=h.lsv2aajhpi56 

## Which issue(s) this PR fixes
[CNTRLPLANE-362](https://issues.redhat.com//browse/CNTRLPLANE-362) 

## Checklist

- [ ] Subject and description added to both, commit and PR.
- [ ] Relevant issues have been referenced.
- [ ] This change includes docs.
- [ ] This change includes unit tests.


Diff:
diff --git a/examples/kubevirt/02-dpa-kubevirt.yaml b/examples/kubevirt/02-dpa-kubevirt.yaml
new file mode 100644
index 000000000..3ee7831b1
--- /dev/null
+++ b/examples/kubevirt/02-dpa-kubevirt.yaml
@@ -0,0 +1,45 @@
+apiVersion: oadp.openshift.io/v1alpha1
+kind: DataProtectionApplication
+metadata:
+  name: dpa-instance
+  namespace: openshift-adp
+spec:
+  backupLocations:
+    - name: default
+      velero:
+        config:
+          region: minio
+          profile: "default"
+          s3ForcePathStyle: 'true'
+          s3Url: 'http://registry.hypershiftbm-2.lab:9002'
+        credential:
+          key: cloud
+          name: cloud-credentials
+        default: true
+        objectStorage:
+          bucket: example-oadp
+          prefix: backup-objects
+        provider: aws
+  snapshotLocations:
+    - velero:
+        provider: aws
+        config:
+          region: region-one
+          profile: "default"
+        credential:
+          key: cloud
+          name: cloud-credentials
+  configuration:
+    nodeAgent:
+      enable: true
+      uploaderType: kopia
+    velero:
+      defaultPlugins:
+        - openshift
+        - aws
+        - kubevirt
+        - csi
+      customPlugins:
+        - name: hypershift-oadp-plugin
+          image: quay.io/hypershift/hypershift-oadp-plugin:latest
+      resourceTimeout: 2h
diff --git a/examples/kubevirt/03-backup-kubevirt.yaml b/examples/kubevirt/03-backup-kubevirt.yaml
new file mode 100644
index 000000000..4783cef7b
--- /dev/null
+++ b/examples/kubevirt/03-backup-kubevirt.yaml
@@ -0,0 +1,42 @@
+apiVersion: velero.io/v1
+kind: Backup
+metadata:
+  name: hcp-osp-backup
+  namespace: openshift-adp
+  labels:
+    velero.io/storage-location: default
+spec:
+  includedNamespaces:
+  - clusters
+  - clusters-example-hosted
+  includedResources:
+  - sa
+  - role
+  - rolebinding
+  - deployment
+  - statefulset
+  - pv
+  - pvc
+  - bmh
+  - configmap
+  - infraenv
+  - priorityclasses
+  - pdb
+  - hostedcluster
+  - nodepool
+  - secrets
+  - hostedcontrolplane
+  - cluster
+  - kubevirtcluster
+  - kubevirtmachinetemplate
+  - datavolume
+  - service
+  - route
+  excludedResources: []
+  storageLocation: default
+  preserveNodePorts: true
+  ttl: 720h0m0s
+  snapshotMoveData: true
+  datamover: "velero"
+  defaultVolumesToFsBackup: false
+  snapshotVolumes: true
diff --git a/examples/kubevirt/04-restore-kubevirt.yaml b/examples/kubevirt/04-restore-kubevirt.yaml
new file mode 100644
index 000000000..c0f33742b
--- /dev/null
+++ b/examples/kubevirt/04-restore-kubevirt.yaml
@@ -0,0 +1,24 @@
+apiVersion: velero.io/v1
+kind: Restore
+metadata:
+  name: hcp-kubevirt-restore
+  namespace: openshift-adp
+spec:
+  includedNamespaces:
+    - clusters
+    - clusters-example-hosted
+  backupName: hcp-kubevirt-backup
+  cleanupBeforeRestore: CleanupRestored
+  veleroManagedClustersBackupName: hcp-kubevirt-backup
+  veleroCredentialsBackupName: hcp-kubevirt-backup
+  veleroResourcesBackupName: hcp-kubevirt-backup
+  restorePVs: true
+  preserveNodePorts: true
+  existingResourcePolicy: update
+  excludedResources:
+    - nodes
+    - events
+    - events.events.k8s.io
+    - backups.velero.io
+    - restores.velero.io
+    - resticrepositories.velero.io
diff --git a/examples/kubevirt/README.md b/examples/kubevirt/README.md
new file mode 100644
index 000000000..763d33ecd
--- /dev/null
+++ b/examples/kubevirt/README.md
@@ -0,0 +1,12 @@
+# KubeVirt Backup/Restore sample objects
+
+⚠️ **IMPORTANT**: These are just sample configurations associated with the provider marked in each folder. Before applying any configuration to your OpenShift cluster, please carefully review and adjust all parameters according to your specific environment and requirements.
+
+This directory contains sample objects specifically for the KubeVirt provider. These examples demonstrate how to configure backup and restore operations in an KubeVirt environment.
+
+## Important Notes
+
+- This configuration is specifically designed for KubeVirt environments
+- Node readoption is not currently supported. In case of node failures, reprovisioning of nodes will be required
+- Please review the [RedHat official documentation](https://docs.okd.io/latest/backup_and_restore/application_backup_and_restore/installing/installing-oadp-mcg.html#installing-oadp-mcg) for detailed information on how OADP works
+- Always validate the configuration before applying it to your environment
diff --git a/pkg/common/types.go b/pkg/common/types.go
index 89ff2e95a..24593fe35 100644
--- a/pkg/common/types.go
+++ b/pkg/common/types.go
@@ -21,6 +21,7 @@ const (
 	defaultWaitForTimeout       time.Duration = 5 * time.Minute
 
 	DefaultK8sSAFilePath string = "/var/run/secrets/kubernetes.io/serviceaccount"
+	KubevirtRHCOSLabel   string = "hypershift.openshift.io/is-kubevirt-rhcos"
 )
 
 var (
diff --git a/pkg/core/backup.go b/pkg/core/backup.go
index e8cefa837..7e3249e9c 100644
--- a/pkg/core/backup.go
+++ b/pkg/core/backup.go
@@ -187,6 +187,17 @@ func (p *BackupPlugin) Execute(item runtime.Unstructured, backup *velerov1.Backu
 				return nil, nil, fmt.Errorf("error performing migration tasks for agent platform: %v", err)
 			}
 		}
+
+	case kind == "DataVolume" || kind == "PersistentVolumeClaim":
+		metadata, err := meta.Accessor(item)
+		if err != nil {
+			return nil, nil, fmt.Errorf("error getting metadata accessor: %v", err)
+		}
+		labels := metadata.GetLabels()
+		if _, exists := labels[common.KubevirtRHCOSLabel]; exists {
+			return nil, nil, nil
+		}
+
 	}
 
 	if (backup.Spec.DefaultVolumesToFsBackup != nil && !*backup.Spec.DefaultVolumesToFsBackup) || backup.Spec.DefaultVolumesToFsBackup == nil {
diff --git a/pkg/core/types/types.go b/pkg/core/types/types.go
index c46075477..2739f79ce 100644
--- a/pkg/core/types/types.go
+++ b/pkg/core/types/types.go
@@ -14,7 +14,7 @@ var (
 	BackupAzureResources      = []string{"azuremachines", "azuremachinetemplates", "azuremanagedmachinepools", "azuremanagedmachinepooltemplates"}
 	BackupIBMPowerVSResources = []string{"ibmpowervsmachines", "ibmpowervsmachinetemplates", "ibmpowervsclusters", "ibmpowervsclustertemplates"}
 	BackupOpenStackResources  = []string{"openstackmachines", "openstackmachinetemplates", "openstackclusters", "openstackclustertemplates"}
-	BackupKubevirtResources   = []string{"kubevirtmachines", "kubevirtmachinetemplates", "kubevirtmachinepools", "kubevirtclusters"}
+	BackupKubevirtResources   = []string{"kubevirtcluster", "kubevirtmachinetemplate", "datavolume"}
 	BackupAgentResources      = []string{"agents", "agentmachines", "agentmachinetemplates", "agentmachinepools", "agentclusters"}
 )
 


Reviews:
user: login: jparrill
body: Thank you so much for the PR!.

Let me add a couple of comments:
- Could you add the DPA, Backup and Restore objects to the examples folder?
- I think we will cover the E2E of this in the Hypershift or the OADP operator repo, so no E2E needed here.
state: CHANGES_REQUESTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-23T08:39:52Z
user: login: LiangquanLi930
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-27T06:35:39Z
user: login: jparrill
body: Small nit, otherwise lgtm
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-28T10:20:53Z

Review comments:
diff_hunk: @@ -187,6 +187,17 @@ func (p *BackupPlugin) Execute(item runtime.Unstructured, backup *velerov1.Backu
 				return nil, nil, fmt.Errorf("error performing migration tasks for agent platform: %v", err)
 			}
 		}
+
+	case kind == "DataVolume" || kind == "PersistentVolumeClaim":
+		metadata, err := meta.Accessor(item)
+		if err != nil {
+			return nil, nil, fmt.Errorf("error getting metadata accessor: %v", err)
+		}
+		labels := metadata.GetLabels()
+		if _, exists := labels[common.KubevirtRHCOSLabel]; exists {
path: pkg/core/backup.go
user: login: jparrill
body: It's necessary to remove the label on restoration? 
created_at: 2025-04-23T08:36:35Z
author_association: CONTRIBUTOR
diff_hunk: @@ -187,6 +187,17 @@ func (p *BackupPlugin) Execute(item runtime.Unstructured, backup *velerov1.Backu
 				return nil, nil, fmt.Errorf("error performing migration tasks for agent platform: %v", err)
 			}
 		}
+
+	case kind == "DataVolume" || kind == "PersistentVolumeClaim":
+		metadata, err := meta.Accessor(item)
+		if err != nil {
+			return nil, nil, fmt.Errorf("error getting metadata accessor: %v", err)
+		}
+		labels := metadata.GetLabels()
+		if _, exists := labels[common.KubevirtRHCOSLabel]; exists {
path: pkg/core/backup.go
user: login: LiangquanLi930
body: AFAIK, we don't need to remove the label on restoration. This label is configured when creating the HostedCluster.
https://github.com/openshift/hypershift/blob/e12e0015930ac82f490078c2e54da470dc13e803/hypershift-operator/controllers/nodepool/kubevirt/kubevirt.go#L221-L232
created_at: 2025-04-27T06:35:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,43 @@
+apiVersion: oadp.openshift.io/v1alpha1
+kind: DataProtectionApplication
+metadata:
+  name: dpa-instance
+  namespace: openshift-adp
+spec:
+  backupLocations:
+    - name: default
+      velero:
+        config:
+          region: region-one
+          profile: "default"
path: examples/kubevirt/02-dpa-kubevirt.yaml
user: login: jparrill
body: small nit, being this for self-manage configuration I would recommend to follow BM example:
```
spec:
  backupLocations:
    - name: default
      velero:
        config:
          region: minio
          profile: "default"
          s3ForcePathStyle: 'true'
          s3Url: 'http://registry.hypershiftbm-2.lab:9002'
``` 
created_at: 2025-04-28T10:20:31Z
author_association: CONTRIBUTOR

PR comments:
user: login: openshift-ci-robot
created_at: 2025-04-23T06:09:48Z
body: @LiangquanLi930: This pull request references [CNTRLPLANE-362](https://issues.redhat.com//browse/CNTRLPLANE-362) which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.19.0" version, but no target version was set.

<details>

In response to [this](https://github.com/openshift/hypershift-oadp-plugin/pull/18):

>## What this PR does / why we need it
>Add support for Kubevirt Platform
>
>## Which issue(s) this PR fixes
>[CNTRLPLANE-362](https://issues.redhat.com//browse/CNTRLPLANE-362) 
>
>## Checklist
>
>- [ ] Subject and description added to both, commit and PR.
>- [ ] Relevant issues have been referenced.
>- [ ] This change includes docs.
>- [ ] This change includes unit tests.


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fhypershift-oadp-plugin).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: openshift-ci-robot
created_at: 2025-04-23T06:15:53Z
body: @LiangquanLi930: This pull request references [CNTRLPLANE-362](https://issues.redhat.com//browse/CNTRLPLANE-362) which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the story to target the "4.19.0" version, but no target version was set.

<details>

In response to [this](https://github.com/openshift/hypershift-oadp-plugin/pull/18):

>## What this PR does / why we need it
>Add support for Kubevirt Platform
>Reference doc: https://docs.google.com/document/d/1MsqSi-fAaJD7s1Kee1ty83DsfNBasneq2Slw8Xc9imE/edit?tab=t.0#heading=h.lsv2aajhpi56 
>
>## Which issue(s) this PR fixes
>[CNTRLPLANE-362](https://issues.redhat.com//browse/CNTRLPLANE-362) 
>
>## Checklist
>
>- [ ] Subject and description added to both, commit and PR.
>- [ ] Relevant issues have been referenced.
>- [ ] This change includes docs.
>- [ ] This change includes unit tests.


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fhypershift-oadp-plugin).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: openshift-ci[bot]
created_at: 2025-04-29T05:27:55Z
body: @LiangquanLi930: all tests **passed!**


[Full PR test history](https://prow.ci.openshift.org/pr-history?org=openshift&repo=hypershift-oadp-plugin&pr=18). [Your PR dashboard](https://prow.ci.openshift.org/pr?query=is:pr+state:open+author:LiangquanLi930).

<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 -->
author_association: NONE
user: login: jparrill
created_at: 2025-04-29T06:49:31Z
body: /approve
author_association: CONTRIBUTOR
user: login: jparrill
created_at: 2025-04-29T06:49:39Z
body: /lgtm
author_association: CONTRIBUTOR
user: login: openshift-ci[bot]
created_at: 2025-04-29T06:49:44Z
body: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/openshift/hypershift-oadp-plugin/pull/18#issuecomment-2837670406" title="Approved">jparrill</a>*, *<a href="https://github.com/openshift/hypershift-oadp-plugin/pull/18#" title="Author self-approved">LiangquanLi930</a>*

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

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/openshift/hypershift-oadp-plugin/blob/main/OWNERS)~~ [jparrill]

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":[]} -->
author_association: NONE
user: login: jparrill
created_at: 2025-04-29T07:39:29Z
body: /jira backport oadp-1.5
author_association: CONTRIBUTOR
user: login: openshift-ci-robot
created_at: 2025-04-29T07:39:31Z
body: @jparrill: The following backport issues have been created:


Queuing cherrypicks to the requested branches to be created after this PR merges:
/cherrypick oadp-1.5

<details>

In response to [this](https://github.com/openshift/hypershift-oadp-plugin/pull/18#issuecomment-2837812599):

>/jira backport oadp-1.5


Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fhypershift-oadp-plugin).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
</details>
author_association: NONE
user: login: openshift-cherrypick-robot
created_at: 2025-04-29T07:40:11Z
body: @openshift-ci-robot: new pull request created: #39

<details>

In response to [this](https://github.com/openshift/hypershift-oadp-plugin/pull/18#issuecomment-2837812876):

>@jparrill: The following backport issues have been created:
>
>
>Queuing cherrypicks to the requested branches to be created after this PR merges:
>/cherrypick oadp-1.5
>
><details>
>
>In response to [this](https://github.com/openshift/hypershift-oadp-plugin/pull/18#issuecomment-2837812599):
>
>>/jira backport oadp-1.5
>
>
>Instructions for interacting with me using PR comments are available [here](https://prow.ci.openshift.org/command-help?repo=openshift%2Fhypershift-oadp-plugin).  If you have questions or suggestions related to my behavior, please file an issue against the [openshift-eng/jira-lifecycle-plugin](https://github.com/openshift-eng/jira-lifecycle-plugin/issues/new) repository.
></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.
</details>
author_association: NONE