Searching the codebase for BackupItemAction implementations, additional-items logic, and KubeVirt GVR definitions.
Here is how the kubevirt-velero-plugin wires VM-related "additional items" for Velero backup. The design is BackupItemAction → dependency graph (kvgraph) → velero.ResourceIdentifier list, not a separate CRD/GVR registration API.
All backup item actions are registered in main.go:
main.go (Lines 39-43):
RegisterBackupItemAction("kubevirt-velero-plugin/backup-datavolume-action", newDVBackupItemAction).
RegisterBackupItemAction("kubevirt-velero-plugin/backup-pvc-action", newPVCBackupItemAction).
RegisterBackupItemAction("kubevirt-velero-plugin/backup-volumesnapshot-action", newVolumeSnapshotBackupItemAction).
RegisterBackupItemAction("kubevirt-velero-plugin/backup-virtualmachine-action", newVMBackupItemAction).
RegisterBackupItemAction("kubevirt-velero-plugin/backup-virtualmachineinstance-action", newVMIBackupItemAction).There is no central "register these GVRs with Velero" list beyond these BIAs and their AppliesTo() selectors.
Related resource types are defined as schema.GroupResource (group + resource, no version) in pkg/util/kvgraph/util.go:
util.go (Lines 36-46):
// KVObjectGraph represents the graph of objects that can be potentially related to a KubeVirt resource
var KVObjectGraph = map[string]schema.GroupResource{
"virtualmachineinstances": {Group: "kubevirt.io", Resource: "virtualmachineinstances"},
"datavolumes": {Group: "cdi.kubevirt.io", Resource: "datavolumes"},
"controllerrevisions": {Group: "apps", Resource: "controllerrevisions"},
"configmaps": {Group: "", Resource: "configmaps"},
"persistentvolumeclaims": kuberesource.PersistentVolumeClaims,
"serviceaccounts": kuberesource.ServiceAccounts,
"secrets": kuberesource.Secrets,
"pods": kuberesource.Pods,
}Lookup and construction of additional items happens in addVeleroResource():
util.go (Lines 48-56):
func addVeleroResource(name, namespace, resource string, resources []velero.ResourceIdentifier) []velero.ResourceIdentifier {
if groupResource, ok := KVObjectGraph[resource]; ok {
resources = append(resources, velero.ResourceIdentifier{
GroupResource: groupResource,
Namespace: namespace,
Name: name,
})
}
return resources
}Note: Not in KVObjectGraph: VirtualMachineInstancePreset, VirtualMachineInstancetype, VirtualMachinePreference, VirtualMachineInstanceMigration, etc. There are zero references to "preset" under pkg/.
| Function | Lines | Purpose |
|---|---|---|
NewObjectBackupGraph |
32–58 | Dispatches by kind (VirtualMachine, VirtualMachineInstance, DataVolume) |
NewVirtualMachineBackupGraph |
61–88 | VM backup graph |
NewVirtualMachineInstanceBackupGraph |
91–110 | VMI backup graph |
NewDataVolumeBackupGraph |
113–119 | DV → PVC when phase is Succeeded |
addInstanceType/addPreference→ controllerrevisions- If
vm.Status.Created: virtualmachineinstances + launcher pod addCommonVMIObjectGraphonvm.Spec.Template.Spec
- Launcher pod
addCommonVMIObjectGraphonvmi.Spec
- If succeeded: related persistentvolumeclaims
| Function | Lines | Adds |
|---|---|---|
addCommonVMIObjectGraph |
59–62 | Volumes + access credentials |
addVolumeGraph |
65–103 | DVs, PVCs, memory-dump PVCs, ConfigMaps, Secrets, ServiceAccounts, cloud-init Secrets |
addAccessCredentials |
106–114 | SSH/password Secrets |
addLauncherPod |
117–123 | virt-launcher pod |
addInstanceType |
126–130 | Instancetype controllerrevisions |
addPreference |
133–137 | Preference controllerrevisions |
addInstanceTypeMatcherResource |
140–148 | controllerrevisions from status or spec RevisionName |
addBackendPVC |
151–170 | Persistent TPM/EFI backend PVCs |
IsBackendStorageNeededForVMI |
173–174 | Triggers backend PVC lookup |
HasPersistentTPMDevice |
177–180 | |
HasPersistentEFI |
183–188 |
util.go (Lines 65-95):
func addVolumeGraph(vmiSpec v1.VirtualMachineInstanceSpec, vmName, namespace string, resources []velero.ResourceIdentifier) ([]velero.ResourceIdentifier, error) {
for _, volume := range vmiSpec.Volumes {
switch {
case volume.DataVolume != nil:
resources = addVeleroResource(volume.DataVolume.Name, namespace, "datavolumes", resources)
resources = addVeleroResource(volume.DataVolume.Name, namespace, "persistentvolumeclaims", resources)
case volume.PersistentVolumeClaim != nil:
resources = addVeleroResource(volume.PersistentVolumeClaim.ClaimName, namespace, "persistentvolumeclaims", resources)
case volume.MemoryDump != nil:
resources = addVeleroResource(volume.MemoryDump.ClaimName, namespace, "persistentvolumeclaims", resources)
case volume.ConfigMap != nil:
resources = addVeleroResource(volume.ConfigMap.Name, namespace, "configmaps", resources)
case volume.Secret != nil:
resources = addVeleroResource(volume.Secret.SecretName, namespace, "secrets", resources)
case volume.ServiceAccount != nil:
resources = addVeleroResource(volume.ServiceAccount.ServiceAccountName, namespace, "serviceaccounts", resources)
case volume.CloudInitNoCloud != nil:
// ... userData/networkData secrets ...
case volume.CloudInitConfigDrive != nil:
// ... userData/networkData secrets ...
}
}
// ...
}Note: NewObjectBackupGraph exists but is only used in tests (backup_graph_test.go); production code calls the specific NewVirtualMachineBackupGraph / NewVirtualMachineInstanceBackupGraph functions directly from BIAs.
Velero's BIA contract: Execute(...) (runtime.Unstructured, []velero.ResourceIdentifier, error) — the second return value is the additional-items list.
| Method | Lines | Notes |
|---|---|---|
AppliesTo |
55–61 | IncludedResources: ["VirtualMachine"] |
Execute |
65–128 | Calls kvgraph.NewVirtualMachineBackupGraph(vm) at 101–104, returns extra at 128 |
canBeSafelyBackedUp |
132–158 | Validates backup scope (VMI/pods/PVCs in backup spec) via util.IsResourceInBackup |
| Method | Lines | Notes |
|---|---|---|
AppliesTo |
60–66 | IncludedResources: ["VirtualMachineInstance"] |
Execute |
70–122 | Calls kvgraph.NewVirtualMachineInstanceBackupGraph(vmi) at 118, returns extra at 122 |
| Method | Lines | Notes |
|---|---|---|
AppliesTo |
61–68 | PersistentVolumeClaim, DataVolume |
Execute |
73–90 | Dispatches by kind |
handlePVC |
93–121 | Returns empty extra |
handleDataVolume |
124–148 | Returns kvgraph.NewDataVolumeBackupGraph(&dv) at 146 |
| File | Execute Lines | Returns |
|---|---|---|
pkg/plugin/pvc_backup_item_action.go |
55–91 | Empty extra (UID labeling only) |
pkg/plugin/volumesnapshot_backup_item_action.go |
79–136 | Empty extra (PVC UID labeling only) |
pkg/util/util.go checks whether a resource kind is in the backup's include/exclude lists:
IsResourceIncluded— lines 99–112IsResourceExcluded— lines 115–128IsResourceInBackup— lines 145–146
Used by VM/VMI BIAs to fail or warn when, e.g., a running VM backup includes PVCs but not pods/VMI. The plugin still returns additional items even when excluded; Velero filters them (see comment in vm_backup_item_action_test.go around lines 369–370).
Restore uses the same kvgraph helpers but via RestoreItemAction, not backup BIAs:
pkg/plugin/vm_restore_item_action.goline 90:kvgraph.NewVirtualMachineRestoreGraph(vm)pkg/plugin/vmi_restore_item_action.goline 105:kvgraph.NewVirtualMachineInstanceRestoreGraph(vmi)- Graph definitions:
pkg/util/kvgraph/restore_graph.golines 30–64
When Velero backs up a VirtualMachine, VMBackupItemAction.Execute builds this transitive set (Velero then honors backup include/exclude filters):
| Related Resource | Group | Resource | How Added |
|---|---|---|---|
| VirtualMachineInstance | kubevirt.io | virtualmachineinstances | VM graph, if status.created |
| virt-launcher Pod | "" | pods | VM/VMI graph, if running |
| DataVolume | cdi.kubevirt.io | datavolumes | Volume refs |
| PVC | "" | persistentvolumeclaims | DV/PVC/memory-dump/backend storage |
| ConfigMap | "" | configmaps | Volume refs |
| Secret | "" | secrets | Volume + cloud-init + access credentials |
| ServiceAccount | "" | serviceaccounts | Volume refs |
| ControllerRevision | apps | controllerrevisions | Instancetype/preference matchers |
Not handled by this plugin: VirtualMachineInstancePreset, instancetype/preference CRs themselves (only their controller revisions), migrations, snapshots, exports, pools, clones, etc.
If you need preset or instancetype CRs included, that would require extending KVObjectGraph and adding graph-walking logic — it does not exist today.