Skip to content

[WIP] backup: veeam kvm integration#12991

Draft
shwstppr wants to merge 111 commits intoapache:mainfrom
shapeblue:integration-veeam-kvm
Draft

[WIP] backup: veeam kvm integration#12991
shwstppr wants to merge 111 commits intoapache:mainfrom
shapeblue:integration-veeam-kvm

Conversation

@shwstppr
Copy link
Copy Markdown
Contributor

@shwstppr shwstppr commented Apr 9, 2026

Description

This PR introduces the initial implementation of Veeam integration support for KVM in CloudStack by adding a UHAPI-compatible server and image server components.

Veeam Backup & Replication interacts with virtualization platforms using its Universal Hypervisor API (UHAPI). To enable backup and restore workflows for CloudStack-managed KVM environments, this change introduces a UHAPI server that exposes CloudStack resources through a UHAPI-compatible interface.

In addition to the control plane APIs, an image server component is introduced to handle the data transfer operations required during backup and restore workflows.

Architecture

The integration consists of two main components:

  1. UHAPI Server (Control Plane) named CloudStack Veeam Control Service

A lightweight UHAPI server runs inside the CloudStack management server and exposes endpoints under:

/ovirt-engine/api

This server provides inventory discovery APIs required by Veeam and translates CloudStack resources into the structures expected by UHAPI.

The server:

  • exposes infrastructure inventory
  • handles authentication and session tokens
  • maps CloudStack resources to UHAPI-compatible representations
  1. Image Server (Data Plane) named CloudStack Image Service

A separate image server component is introduced to handle backup and restore data transfer operations.

This component:

  • serves disk image data during backup
  • receives image data during restore operations
  • exposes endpoints used by Veeam worker components
  • integrates with CloudStack storage to read and write VM disk data

The separation between both these components server ensures that:

  • metadata APIs and control operations remain lightweight
  • bulk image transfer operations are handled independently

Co-authored by @abh1sar @weizhouapache

Types of changes

  • Breaking change (fix or feature that would cause existing functionality to change)
  • New feature (non-breaking change which adds functionality)
  • Bug fix (non-breaking change which fixes an issue)
  • Enhancement (improves an existing feature and functionality)
  • Cleanup (Code refactoring and cleanup, that may add test cases)
  • Build/CI
  • Test (unit or integration test code)

Feature/Enhancement Scale or Bug Severity

Feature/Enhancement Scale

  • Major
  • Minor

Bug Severity

  • BLOCKER
  • Critical
  • Major
  • Minor
  • Trivial

Screenshots (if appropriate):

How Has This Been Tested?

How did you try to break this feature and the system with this change?

shwstppr and others added 30 commits April 9, 2026 09:38
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
shwstppr and others added 16 commits April 9, 2026 10:30
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
vm

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 9, 2026

Codecov Report

❌ Patch coverage is 2.81833% with 7655 lines in your changes missing coverage. Please review.
✅ Project coverage is 17.76%. Comparing base (c361409) to head (40cadd0).

Files with missing lines Patch % Lines
...apache/cloudstack/veeam/adapter/ServerAdapter.java 0.00% 1075 Missing ⚠️
...rg/apache/cloudstack/veeam/api/dto/OvfXmlUtil.java 10.54% 471 Missing and 21 partials ⚠️
...g/apache/cloudstack/veeam/api/VmsRouteHandler.java 0.00% 378 Missing ⚠️
...n/java/org/apache/cloudstack/veeam/api/dto/Vm.java 18.21% 255 Missing and 1 partial ⚠️
...a/org/apache/cloudstack/veeam/api/dto/Cluster.java 0.00% 212 Missing ⚠️
...java/org/apache/cloudstack/veeam/api/dto/Host.java 0.00% 191 Missing ⚠️
...java/org/apache/cloudstack/veeam/api/dto/Disk.java 0.00% 145 Missing ⚠️
...api/converter/StoreVOToStorageDomainConverter.java 0.00% 144 Missing ⚠️
...apache/cloudstack/veeam/api/dto/StorageDomain.java 0.00% 139 Missing ⚠️
...urce/wrapper/LibvirtStartBackupCommandWrapper.java 1.48% 133 Missing ⚠️
... and 130 more
Additional details and impacted files
@@             Coverage Diff              @@
##               main   #12991      +/-   ##
============================================
- Coverage     18.00%   17.76%   -0.25%     
- Complexity    16466    16502      +36     
============================================
  Files          5977     6101     +124     
  Lines        537777   546461    +8684     
  Branches      66037    66771     +734     
============================================
+ Hits          96844    97061     +217     
- Misses       430011   438446    +8435     
- Partials      10922    10954      +32     
Flag Coverage Δ
uitests 3.52% <ø> (ø)
unittests 18.88% <2.81%> (-0.29%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Signed-off-by: Abhishek Kumar <abhishek.mrt22@gmail.com>
@shwstppr
Copy link
Copy Markdown
Contributor Author

shwstppr commented Apr 9, 2026

@blueorangutan package

@blueorangutan
Copy link
Copy Markdown

@shwstppr a [SL] Jenkins job has been kicked to build packages. It will be bundled with no SystemVM templates. I'll keep you posted as I make progress.

@blueorangutan
Copy link
Copy Markdown

Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 17429

@yadvr yadvr added this to the 4.23.0 milestone Apr 10, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Introduces initial Veeam UHAPI integration for CloudStack KVM by adding a new Veeam control-plane plugin and KVM image/data transfer components, plus schema/API extensions to support checkpointed/incremental backup workflows.

Changes:

  • Added veeam-control-service plugin with UHAPI-compatible DTOs, route handlers wiring, auth/CIDR filters, and serialization utilities.
  • Added KVM image server package (Python) and KVM agent/libvirt wrappers + new agent commands for checkpoints and image transfer lifecycle.
  • Extended DB schema, DAOs, and API responses/commands to persist checkpoint/image-transfer state and support new workflows.

Reviewed changes

Copilot reviewed 183 out of 221 changed files in this pull request and generated 20 comments.

Show a summary per file
File Description
scripts/vm/hypervisor/kvm/imageserver/tests/init.py Adds test package scaffold for the new KVM image server component.
scripts/vm/hypervisor/kvm/imageserver/constants.py Introduces image server constants (ports, paths, tuning).
scripts/vm/hypervisor/kvm/imageserver/concurrency.py Adds per-image concurrency controls for image transfers.
scripts/vm/hypervisor/kvm/imageserver/backends/init.py Backend factory for file/NBD transfer backends.
scripts/vm/hypervisor/kvm/imageserver/main.py Module entrypoint for starting the image server.
scripts/vm/hypervisor/kvm/imageserver/init.py Package-level documentation for the image server.
plugins/pom.xml Registers the new Veeam control service plugin module.
plugins/network-elements/juniper-contrail/src/test/java/org/apache/cloudstack/network/contrail/management/MockAccountManager.java Updates mock to satisfy new/changed account-service API methods.
plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/api/dto/OvfXmlUtilTest.java Adds test coverage for OVF XML parsing into DTOs.
plugins/integrations/veeam-control-service/src/test/java/org/apache/cloudstack/veeam/VeeamControlServiceImplTest.java Adds basic JSON parsing test for ImageTransfer DTO.
plugins/integrations/veeam-control-service/src/main/resources/META-INF/cloudstack/veeam-control-service/spring-veeam-control-service-context.xml Wires Spring beans for route handlers and adapters.
plugins/integrations/veeam-control-service/src/main/resources/META-INF/cloudstack/veeam-control-service/module.properties Declares the new plugin module metadata.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/utils/ResponseWriter.java Adds response serialization helper for XML/JSON.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/utils/PathUtil.java Adds URL path parsing utility for route handlers.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/utils/Negotiation.java Adds Accept-header negotiation for XML vs JSON output.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/utils/Mapper.java Adds Jackson JSON/XML mappers configured for UHAPI-like payloads.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/utils/JwtUtil.java Adds basic JWT issuing helper (HS256).
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/utils/DataUtil.java Adds base64url, JSON escaping, constant-time equals helpers.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/filter/BasicAuthFilter.java Adds Basic Auth enforcement for the Veeam API endpoint.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/filter/AllowedClientCidrsFilter.java Adds CIDR allow-list filtering for inbound requests.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/VnicProfile.java Adds UHAPI DTO for vNIC profiles.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/VmAction.java Adds action DTO for VM-related async operations.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Version.java Adds version DTO and derivation from CloudStack/package version.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Topology.java Adds CPU topology DTO.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Tag.java Adds tag DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/SupportedVersions.java Adds supported-versions DTO wrapper.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/SummaryCount.java Adds summary count DTO.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Storage.java Adds storage DTO used by UHAPI payloads.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/SpecialObjects.java Adds specialObjects DTO for root/blank template refs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Snapshot.java Adds snapshot DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ResourceAction.java Adds base action DTO.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ReportedDevice.java Adds reported device info DTO for NICs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Ref.java Adds lightweight href/id ref DTO helper.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ProductInfo.java Adds product info DTO returned by API root.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Os.java Adds OS DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Nic.java Adds NIC DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Network.java Adds network DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/NamedList.java Adds NamedList wrapper for oVirt-like list payload shape.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Mac.java Adds MAC address DTO.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Link.java Adds link DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Job.java Adds async job DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Ip.java Adds IP DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Fault.java Adds fault DTO for error responses.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/EmptyElementSerializer.java Adds serializer for empty XML element placeholders.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/EmptyElement.java Adds empty element placeholder type.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DiskAttachment.java Adds disk-attachment DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/DataCenter.java Adds datacenter DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Cpu.java Adds CPU DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Checkpoint.java Adds checkpoint DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Certificate.java Adds certificate DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/BaseDto.java Adds base DTO with href/id helpers.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Backup.java Adds backup DTO representation.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/ApiSummary.java Adds API root summary DTO.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/dto/Api.java Adds API root payload DTO for /ovirt-engine/api.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/VmSnapshotVOToSnapshotConverter.java Converts CloudStack VM snapshots to UHAPI snapshot DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/UserVmVOToCheckpointConverter.java Converts VM details into checkpoint DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/ResourceTagVOToTagConverter.java Converts resource tags to tag DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/NetworkVOToVnicProfileConverter.java Converts networks to vNIC profile DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/NetworkVOToNetworkConverter.java Converts networks to UHAPI network DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/ImageTransferVOToImageTransferConverter.java Converts ImageTransfer VO to UHAPI transfer DTO.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/HostJoinVOToHostConverter.java Converts hosts to UHAPI host DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/DataCenterJoinVOToDataCenterConverter.java Converts zones to UHAPI datacenter DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/api/converter/AsyncJobJoinVOToJobConverter.java Converts async jobs to UHAPI job/action DTOs.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ApiAccessInterceptor.java Adds AOP interceptor to enforce API permissions.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/adapter/ApiAccess.java Adds annotation to mark methods requiring API permission checks.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/VeeamControlService.java Adds configurable service interface and config keys.
plugins/integrations/veeam-control-service/src/main/java/org/apache/cloudstack/veeam/RouteHandler.java Adds route handler abstraction for servlet routing.
plugins/integrations/veeam-control-service/pom.xml Adds Maven module definition for the new plugin.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStopNBDServerCommandWrapper.java Stops qemu-nbd systemd services used for transfers.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtStopBackupCommandWrapper.java Adds backup-stop behavior via libvirt/virsh.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetImageTransferProgressCommandWrapper.java Adds progress reporting for image transfers on KVM.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtDeleteVmCheckpointCommandWrapper.java Adds checkpoint deletion logic on KVM.
plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java Adds image server path/props + extra KVM helper method(s).
framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDaoImpl.java Adds DAO query for pending jobs by account.
framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/dao/AsyncJobDao.java Adds DAO method signature for pending jobs by account.
engine/userdata/src/main/java/org/apache/cloudstack/userdata/UserDataManagerImpl.java Simplifies HTTP method selection for userdata decode limits.
engine/schema/src/main/resources/META-INF/db/views/cloud.user_vm_view.sql Extends VM view to include guest OS display name.
engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql Adds backup checkpoint fields + creates image_transfer table.
engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql Minor schema formatting cleanup.
engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml Registers imageTransferDaoImpl bean.
engine/schema/src/main/java/org/apache/cloudstack/backup/dao/ImageTransferDao.java Adds DAO interface for ImageTransfer persistence.
engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java Persists checkpoint, host tracking fields in backups.
engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java Adds query for VM IDs by host/lastHost for volume stats.
engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java Adds DAO method signature for VM IDs by host/lastHost.
engine/schema/src/main/java/com/cloud/tags/dao/ResourceTagsDaoImpl.java Adds tag lookup helpers by owners/key/value.
engine/schema/src/main/java/com/cloud/tags/dao/ResourceTagDao.java Adds new tag DAO APIs with filter support.
engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDaoImpl.java Adds template lookup by account+name.
engine/schema/src/main/java/com/cloud/storage/dao/VMTemplateDao.java Adds DAO method signature for account+name template lookup.
engine/schema/src/main/java/com/cloud/network/dao/NetworkDaoImpl.java Adds filtering/owner-aware network list query.
engine/schema/src/main/java/com/cloud/network/dao/NetworkDao.java Adds new network DAO signatures with filters/owners.
engine/schema/src/main/java/com/cloud/dc/dao/ClusterDaoImpl.java Adds filtered listing by hypervisor type.
engine/schema/src/main/java/com/cloud/dc/dao/ClusterDao.java Adds DAO method signature for filtered listing by hypervisor type.
engine/orchestration/src/main/resources/META-INF/cloudstack/core/spring-engine-orchestration-core-context.xml Registers KVM backup export service in adapter map.
engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java Adds “blank instance” short-circuit during allocation.
core/src/main/java/org/apache/cloudstack/backup/StopNBDServerCommand.java Adds agent command to stop NBD service for transfer.
core/src/main/java/org/apache/cloudstack/backup/StopBackupCommand.java Adds agent command to abort backup job.
core/src/main/java/org/apache/cloudstack/backup/StopBackupAnswer.java Adds answer type for StopBackupCommand.
core/src/main/java/org/apache/cloudstack/backup/StartNBDServerCommand.java Adds agent command to start NBD server.
core/src/main/java/org/apache/cloudstack/backup/StartNBDServerAnswer.java Adds answer type for StartNBDServerCommand.
core/src/main/java/org/apache/cloudstack/backup/StartBackupCommand.java Adds agent command for starting checkpoint-based backup.
core/src/main/java/org/apache/cloudstack/backup/StartBackupAnswer.java Adds answer type returning checkpoint create time.
core/src/main/java/org/apache/cloudstack/backup/GetImageTransferProgressCommand.java Adds agent command to retrieve transfer progress.
core/src/main/java/org/apache/cloudstack/backup/GetImageTransferProgressAnswer.java Adds answer type carrying progress map.
core/src/main/java/org/apache/cloudstack/backup/FinalizeImageTransferCommand.java Adds agent command to finalize transfers.
core/src/main/java/org/apache/cloudstack/backup/DeleteVmCheckpointCommand.java Adds agent command to delete VM checkpoints/bitmaps.
core/src/main/java/org/apache/cloudstack/backup/CreateImageTransferCommand.java Adds agent command for registering image transfers.
core/src/main/java/org/apache/cloudstack/backup/CreateImageTransferAnswer.java Adds answer type for CreateImageTransferCommand.
client/pom.xml Adds dependency on the new Veeam control service plugin.
api/src/main/java/org/apache/cloudstack/backup/ImageTransfer.java Adds ImageTransfer API model and enums.
api/src/main/java/org/apache/cloudstack/backup/BackupManager.java Updates backup provider config description.
api/src/main/java/org/apache/cloudstack/backup/Backup.java Adds checkpoint fields + new backup status states.
api/src/main/java/org/apache/cloudstack/api/response/ImageTransferResponse.java Adds API response type for image transfer listing/creation.
api/src/main/java/org/apache/cloudstack/api/response/CheckpointResponse.java Adds API response type for VM checkpoints.
api/src/main/java/org/apache/cloudstack/api/response/BackupResponse.java Adds checkpoint/host fields to backup response.
api/src/main/java/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java Adds storage pool selection parameter + validation.
api/src/main/java/org/apache/cloudstack/api/command/user/volume/AssignVolumeCmd.java Adds setters to facilitate programmatic usage.
api/src/main/java/org/apache/cloudstack/api/command/user/vm/AddNicToVMCmd.java Adds setters to facilitate programmatic usage.
api/src/main/java/org/apache/cloudstack/api/command/user/offering/ListServiceOfferingsCmd.java Adds setters to facilitate programmatic usage.
api/src/main/java/org/apache/cloudstack/api/command/admin/vm/DeployVMCmdByAdmin.java Adds setter for cluster ID.
api/src/main/java/org/apache/cloudstack/api/command/admin/vm/AssignVMCmd.java Adds skipNetwork flag + setters for programmatic usage.
api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ListVmCheckpointsCmd.java Adds admin-only checkpoint listing test API.
api/src/main/java/org/apache/cloudstack/api/command/admin/backup/ListImageTransfersCmd.java Adds admin-only image transfer listing test API.
api/src/main/java/org/apache/cloudstack/api/command/admin/backup/FinalizeImageTransferCmd.java Adds admin-only transfer finalization test API.
api/src/main/java/org/apache/cloudstack/api/command/admin/backup/FinalizeBackupCmd.java Adds admin-only backup finalization test API.
api/src/main/java/org/apache/cloudstack/api/command/admin/backup/DeleteVmCheckpointCmd.java Adds admin-only checkpoint deletion test API.
api/src/main/java/org/apache/cloudstack/api/command/admin/backup/CreateImageTransferCmd.java Adds admin-only image transfer creation test API.
api/src/main/java/org/apache/cloudstack/api/ApiServerService.java Adds interface method for async command processing.
api/src/main/java/org/apache/cloudstack/api/ApiConstants.java Adds constants for new API fields.
api/src/main/java/com/cloud/vm/VmDetailConstants.java Adds VM detail keys for checkpoint tracking.
api/src/main/java/com/cloud/user/AccountService.java Adds account lookup by UUID + user lookup convenience method.
api/src/main/java/com/cloud/storage/VolumeApiService.java Adds overloads for programmatic volume alloc/create + helpers.
agent/src/main/java/com/cloud/agent/properties/AgentProperties.java Adds agent config keys for image server TLS/listen address.
agent/conf/agent.properties Documents and adds image-server-related agent properties.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

public static DataCenter toDataCenter(final DataCenterJoinVO zone) {
final String id = zone.getUuid();
final String basePath = VeeamControlService.ContextPath.value();
final String href = basePath + DataCentersRouteHandler.BASE_ROUTE + DataCentersRouteHandler.BASE_ROUTE + "/" + id;
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The href concatenation duplicates BASE_ROUTE, producing an incorrect URL. Also, Link.of(rel, href) is being called with parameters reversed (rel is being set to a URL and href to a literal like clusters). Build href as basePath + BASE_ROUTE + \"/\" + id, and construct links as Link.of(\"clusters\", href + \"/clusters\") (same for networks/storagedomains).

Copilot uses AI. Check for mistakes.
Comment on lines +64 to +68
dc.link = Arrays.asList(
Link.of(href + "/clusters", "clusters"),
Link.of(href + "/networks", "networks"),
Link.of(href + "/storagedomains", "storagedomains")
);
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The href concatenation duplicates BASE_ROUTE, producing an incorrect URL. Also, Link.of(rel, href) is being called with parameters reversed (rel is being set to a URL and href to a literal like clusters). Build href as basePath + BASE_ROUTE + \"/\" + id, and construct links as Link.of(\"clusters\", href + \"/clusters\") (same for networks/storagedomains).

Copilot uses AI. Check for mistakes.
Comment on lines +580 to +581
logger.debug("Template is a dummy template for hypervisor {}, skipping volume allocation", hyperType);
return;
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning from allocate(...) when the template is a blank/dummy template likely aborts the rest of the VM allocation flow (beyond root volume allocation). If the intent is only to skip root volume allocation, avoid return here and instead conditionally skip allocateRootVolume(...) while letting the method continue.

Suggested change
logger.debug("Template is a dummy template for hypervisor {}, skipping volume allocation", hyperType);
return;
logger.debug("Template is a dummy template for hypervisor {}, skipping root volume allocation", hyperType);

Copilot uses AI. Check for mistakes.

public CreateImageTransferCommand(String transferId, String direction, String socket, String file, int idleTimeoutSeconds) {
this(transferId, direction, socket, idleTimeoutSeconds);
if (direction == ImageTransfer.Direction.download.toString()) {
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

String comparison uses ==, so the download check can fail unexpectedly. Use .equals(...) (or parse direction into ImageTransfer.Direction and compare enums) to reliably reject the file backend for downloads.

Suggested change
if (direction == ImageTransfer.Direction.download.toString()) {
if (ImageTransfer.Direction.download.toString().equals(direction)) {

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +68
LOGGER.warn("Failed to inject VeeamControlService, allowing request by default");
chain.doFilter(request, response);
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failing open when VeeamControlService injection is missing makes the allow-list enforcement ineffective and can unintentionally expose the endpoint. Prefer failing closed (e.g., return 503/500) or at least deny with 403 when CIDR enforcement cannot be evaluated.

Suggested change
LOGGER.warn("Failed to inject VeeamControlService, allowing request by default");
chain.doFilter(request, response);
LOGGER.error("Failed to inject VeeamControlService, rejecting request because allowed client CIDRs cannot be evaluated");
resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Service Unavailable");

Copilot uses AI. Check for mistakes.
Comment on lines +130 to +134
@SerializedName("from_checkpoint_id")
@Param(description = "Previous active checkpoint id for incremental backups", since = "4.22.0")
private String fromCheckpointId;

@SerializedName("to_checkpoint_id")
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These new response field names use underscores (from_checkpoint_id, to_checkpoint_id), which is inconsistent with typical CloudStack API response naming (commonly lower-cased without underscores like backupid, vmid, etc.). Consider aligning the serialized names with existing conventions to minimize client surprises and maintain consistency.

Suggested change
@SerializedName("from_checkpoint_id")
@Param(description = "Previous active checkpoint id for incremental backups", since = "4.22.0")
private String fromCheckpointId;
@SerializedName("to_checkpoint_id")
@SerializedName("fromcheckpointid")
@Param(description = "Previous active checkpoint id for incremental backups", since = "4.22.0")
private String fromCheckpointId;
@SerializedName("tocheckpointid")

Copilot uses AI. Check for mistakes.
Comment on lines +23 to +24
private NamedList<Ip> ips;
private Mac Mac;
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Field name Mac is capitalized, which is inconsistent with Java conventions and makes the code harder to read/maintain. Rename the field to mac and update getters/setters accordingly (method names can remain getMac/setMac).

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +59
public Mac getMac() {
return Mac;
}

public void setMac(Mac mac) {
Mac = mac;
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Field name Mac is capitalized, which is inconsistent with Java conventions and makes the code harder to read/maintain. Rename the field to mac and update getters/setters accordingly (method names can remain getMac/setMac).

Copilot uses AI. Check for mistakes.
Comment on lines +31 to +73

if (StringUtils.isBlank(path)) {
return null;
}

// Remove base route (be tolerant of trailing slash in baseRoute)
String rest = path;
if (StringUtils.isNotBlank(baseRoute)) {
String normalizedBase = baseRoute.endsWith("/") && baseRoute.length() > 1
? baseRoute.substring(0, baseRoute.length() - 1)
: baseRoute;
if (rest.startsWith(normalizedBase)) {
rest = rest.substring(normalizedBase.length());
}
}

// Expect "/{id}" or "/{id}/..." (no empty segments)
if (StringUtils.isBlank(rest) || !rest.startsWith("/")) {
return null; // /api/datacenters (no id) or invalid format
}

rest = rest.substring(1); // remove leading '/'

if (StringUtils.isBlank(rest)) {
return null;
}

final String[] parts = rest.split("/", -1);

// Collect non-blank segments
List<String> validParts = new ArrayList<>();
for (String part : parts) {
if (StringUtils.isNotBlank(part)) {
validParts.add(part);
}
}

// Validate first segment is a UUID
if (validParts.isEmpty() || (CONSIDER_ONLY_UUID_AS_ID && !UuidUtils.isUuid(validParts.get(0)))) {
return null;
}

return validParts;
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation is inconsistent, and the UUID validation comment does not match behavior when CONSIDER_ONLY_UUID_AS_ID is false (no UUID validation occurs). Consider either enabling UUID validation (and enforcing it), or updating the comment/logic to reflect the intended contract; also prefer returning an empty list (or an Optional) instead of null to simplify callers.

Suggested change
if (StringUtils.isBlank(path)) {
return null;
}
// Remove base route (be tolerant of trailing slash in baseRoute)
String rest = path;
if (StringUtils.isNotBlank(baseRoute)) {
String normalizedBase = baseRoute.endsWith("/") && baseRoute.length() > 1
? baseRoute.substring(0, baseRoute.length() - 1)
: baseRoute;
if (rest.startsWith(normalizedBase)) {
rest = rest.substring(normalizedBase.length());
}
}
// Expect "/{id}" or "/{id}/..." (no empty segments)
if (StringUtils.isBlank(rest) || !rest.startsWith("/")) {
return null; // /api/datacenters (no id) or invalid format
}
rest = rest.substring(1); // remove leading '/'
if (StringUtils.isBlank(rest)) {
return null;
}
final String[] parts = rest.split("/", -1);
// Collect non-blank segments
List<String> validParts = new ArrayList<>();
for (String part : parts) {
if (StringUtils.isNotBlank(part)) {
validParts.add(part);
}
}
// Validate first segment is a UUID
if (validParts.isEmpty() || (CONSIDER_ONLY_UUID_AS_ID && !UuidUtils.isUuid(validParts.get(0)))) {
return null;
}
return validParts;
if (StringUtils.isBlank(path)) {
return new ArrayList<>();
}
// Remove base route (be tolerant of trailing slash in baseRoute)
String rest = path;
if (StringUtils.isNotBlank(baseRoute)) {
String normalizedBase = baseRoute.endsWith("/") && baseRoute.length() > 1
? baseRoute.substring(0, baseRoute.length() - 1)
: baseRoute;
if (rest.startsWith(normalizedBase)) {
rest = rest.substring(normalizedBase.length());
}
}
// Expect "/{id}" or "/{id}/..." (no empty segments)
if (StringUtils.isBlank(rest) || !rest.startsWith("/")) {
return new ArrayList<>(); // /api/datacenters (no id) or invalid format
}
rest = rest.substring(1); // remove leading '/'
if (StringUtils.isBlank(rest)) {
return new ArrayList<>();
}
final String[] parts = rest.split("/", -1);
// Collect non-blank segments
List<String> validParts = new ArrayList<>();
for (String part : parts) {
if (StringUtils.isNotBlank(part)) {
validParts.add(part);
}
}
// Ensure the first segment exists; validate it as a UUID only when configured to do so
if (validParts.isEmpty() || (CONSIDER_ONLY_UUID_AS_ID && !UuidUtils.isUuid(validParts.get(0)))) {
return new ArrayList<>();
}
return validParts;

Copilot uses AI. Check for mistakes.
Comment on lines +68 to +71
// Validate first segment is a UUID
if (validParts.isEmpty() || (CONSIDER_ONLY_UUID_AS_ID && !UuidUtils.isUuid(validParts.get(0)))) {
return null;
}
Copy link

Copilot AI Apr 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation is inconsistent, and the UUID validation comment does not match behavior when CONSIDER_ONLY_UUID_AS_ID is false (no UUID validation occurs). Consider either enabling UUID validation (and enforcing it), or updating the comment/logic to reflect the intended contract; also prefer returning an empty list (or an Optional) instead of null to simplify callers.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants