Fixes issue with loading Capacity dashboard when mulitple backup providers configured#12550
Fixes issue with loading Capacity dashboard when mulitple backup providers configured#12550
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## 4.20 #12550 +/- ##
============================================
+ Coverage 16.26% 16.37% +0.11%
- Complexity 13428 13624 +196
============================================
Files 5660 5662 +2
Lines 499907 502494 +2587
Branches 60696 61844 +1148
============================================
+ Hits 81316 82296 +980
- Misses 409521 411072 +1551
- Partials 9070 9126 +56
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
@blueorangutan package |
|
@Pearl1594 a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
@abh1sar @DaanHoogland I've added this bit : 94ac3ea to add a validator that can be used for any configuration. Do you think this is useful? |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16636 |
|
@blueorangutan package |
|
@Pearl1594 a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16639 |
api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
Outdated
Show resolved
Hide resolved
api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
Outdated
Show resolved
Hide resolved
api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
Outdated
Show resolved
Hide resolved
api/src/main/java/org/apache/cloudstack/backup/BackupManager.java
Outdated
Show resolved
Hide resolved
framework/config/src/main/java/org/apache/cloudstack/framework/config/ValidatedConfigKey.java
Outdated
Show resolved
Hide resolved
abh1sar
left a comment
There was a problem hiding this comment.
Code LGTM.
just a few nitpicks.
| "dummy", | ||
| "The backup and recovery provider plugin.", true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key()); | ||
| "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas", | ||
| true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key(), value -> validateBackupProviderConfig((String)value)); |
There was a problem hiding this comment.
| true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key(), value -> validateBackupProviderConfig((String)value)); | |
| true, ConfigKey.Scope.Zone, BackupFrameworkEnabled.key(), value -> validateBackupProviderConfig((String) value)); |
| throw new CloudRuntimeException("Invalid backup provider name provided"); | ||
| } | ||
| if (!backupProvidersMap.containsKey(name)) { | ||
| String[] backupProviderNames = name.split(","); |
There was a problem hiding this comment.
This is not possible now, right?
There was a problem hiding this comment.
I don't think so, currently, ACS allows taking any string as input, so if we provide a comma separated string, it would compare that with providers supported in ACS, and would fail and report Cannot find backup provider by name: dummy,nas (if both were set)
There was a problem hiding this comment.
I meant that validator will not allow , in the name, so no need for splitting the name by comma. We can revert to old code.
There was a problem hiding this comment.
--@abh1sar , what do you mean by “the validator”? are you talking about the ui/service/manager…—
never mind, got it.
There was a problem hiding this comment.
You're right, with the validator - this isn't required.
|
@Pearl1594 , can you address @abh1sar ’s comments? |
|
@blueorangutan package |
|
@DaanHoogland a [SL] Jenkins job has been kicked to build packages. It will be bundled with KVM, XenServer and VMware SystemVM templates. I'll keep you posted as I make progress. |
|
Packaging result [SF]: ✔️ el8 ✔️ el9 ✔️ el10 ✔️ debian ✔️ suse15. SL-JID 16698 |
| if (value != null && (value.contains(",") || value.trim().contains(" "))) { | ||
| throw new IllegalArgumentException("Multiple backup provider plugins are not supported. Please provide a single plugin value."); | ||
| } | ||
| List<String> validPlugins = List.of("dummy", "veeam", "networker", "nas"); |
There was a problem hiding this comment.
can check these values with the enum?
There was a problem hiding this comment.
we don't have enums - do you want me to create one?
abh1sar
left a comment
There was a problem hiding this comment.
Code LGTM. Thanks @Pearl1594 .
|
@Pearl1594 , I never answerred this query; I think it is great, I wonder though if it shouldn’t just be part of |
There was a problem hiding this comment.
@Pearl1594, I have tested the PR and the core fix works well. Two issues found:
1. Case-sensitivity mismatch between validator and runtime provider lookup
The validator accepts values like DUMMY, Veeam, nAS (due to .toLowerCase()) but backupProvidersMap lookup is case-sensitive, causing runtime failures. We can potentially normalize the value to lowercase before storing, or reject non-lowercase values.
2. Empty string accepted via API
Setting the value to empty string via API bypasses validation (value != null check doesn't catch it). Suggested fix: add an empty/blank check (unless this is a common api behavior in such cases)
Test Execution Summary
| TC | Name | Result |
|---|---|---|
| TC1 | Reject comma-separated multiple providers | PASS |
| TC2 | Reject space-separated multiple providers | PASS |
| TC3 | Reject invalid provider names | FAIL (case-sensitivity bug) |
| TC4 | Accept valid single providers | PASS |
| TC5 | Accept null/empty handling | PASS with observation |
| TC6 | Capacity dashboard loads with valid provider | PASS |
| TC7 | Capacity dashboard after MS restart | PASS |
| TC9 | Zone-scoped setting validation | PASS |
| TC10 | BackupManagerImpl indentation fix | PASS |
Detailed Test Report
TC1: Reject comma-separated multiple providers
Objective
Verify that setting backup.framework.provider.plugin to a comma-separated list of multiple providers is rejected with an appropriate error message, both via UI and API.
Test Steps
- Navigate to Configuration → Global Settings, search for
backup.framework.provider.plugin - Set the value to
dummy,nasand click save — observe the error in UI - Via CloudMonkey, run:
update configuration name=backup.framework.provider.plugin value=dummy,nasupdate configuration name=backup.framework.provider.plugin value=veeam,networkerupdate configuration name=backup.framework.provider.plugin value=dummy,veeam,nas
- Check management server logs:
grep -i "Multiple backup provider" /var/log/cloudstack/management/management-server.log | tail -5
Expected Result:
All attempts to set multiple comma-separated backup providers should be rejected with error: "Multiple backup provider plugins are not supported. Please provide a single plugin value." — both in UI and via API.
Actual Result:
All attempts were correctly rejected. The UI displayed an error dialog with the expected message and a red banner "There was an error saving this setting." The API returned HTTP 431 with error code 9999 and the same error message for all three comma-separated values. The management server log confirmed the validation was triggered.
Test Evidence:
UI: Error dialog displayed "Multiple backup provider plugins are not supported. Please provide a single plugin value." with red error banner. The setting value remained unchanged at dummy.
Screencast.from.2026-02-06.12-24-14.webm
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=dummy,nas
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=veeam,networker
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=dummy,veeam,nas
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
Management server log:
2026-02-06 10:22:45,925 INFO [c.c.a.ApiServer] (qtp2038105753-21:[ctx-996c2d83, ctx-eefc2ddd]) (logid:e070c0d6) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:23:11,075 INFO [c.c.a.ApiServer] (qtp2038105753-21:[ctx-347a8d8c, ctx-57f3836c]) (logid:22aaebb0) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:23:41,775 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-2a51a0f6, ctx-069f267d, ctx-34cfe07f]) (logid:aa1bb78b) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:23:45,841 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-79c5561e, ctx-2dde040d, ctx-60b040c1]) (logid:3ef84978) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:23:47,790 INFO [c.c.a.ApiServer] (qtp2038105753-21:[ctx-08b58f4a, ctx-79177dab, ctx-cfcbee6b]) (logid:24e48a85) Multiple backup provider plugins are not supported. Please provide a single plugin value.
Test Result: PASS
TC2: Reject space-separated multiple providers
Objective
Verify that setting backup.framework.provider.plugin to space-separated or comma-plus-space-separated values is rejected with an appropriate error message, both via UI and API.
Test Steps
- Via CloudMonkey, run:
update configuration name=backup.framework.provider.plugin value="dummy nas"update configuration name=backup.framework.provider.plugin value="veeam networker"update configuration name=backup.framework.provider.plugin value="dummy, nas"
- In the UI, navigate to Configuration → Global Settings, search for
backup.framework.provider.plugin, set the value todummy nasand click save - Check management server logs:
grep -i "Multiple backup provider" /var/log/cloudstack/management/management-server.log | tail -10
Expected Result:
All attempts to set space-separated or comma-plus-space-separated backup providers should be rejected with error: "Multiple backup provider plugins are not supported. Please provide a single plugin value."
Actual Result:
All attempts were correctly rejected. The API returned HTTP 431 with error code 9999 and the expected error message for all three variations. The UI also displayed an error when dummy nas was entered. Management server logs confirmed all validation rejections.
Test Evidence:
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value="dummy nas"
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value="veeam networker"
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value="dummy, nas"
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
UI: Setting dummy nas in the Global Settings UI resulted in an error.
Screencast.from.2026-02-06.12-26-01.webm
Management server log:
2026-02-06 10:24:17,864 INFO [c.c.a.ApiServer] (qtp2038105753-21:[ctx-46bed86b, ctx-31a1a970]) (logid:429e3f21) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:25:36,232 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-81d96d87, ctx-ee7ee4d7, ctx-d7dfe3e1]) (logid:97150bbc) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:25:39,685 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-3dcf8de1, ctx-3d5104dc, ctx-801436da]) (logid:6b16d926) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:25:41,472 INFO [c.c.a.ApiServer] (qtp2038105753-21:[ctx-cfde9084, ctx-62e2fba0, ctx-b9c017a5]) (logid:afc9b8a5) Multiple backup provider plugins are not supported. Please provide a single plugin value.
2026-02-06 10:26:04,463 INFO [c.c.a.ApiServer] (qtp2038105753-21:[ctx-9fb6652b, ctx-cddfc279]) (logid:013ee8ee) Multiple backup provider plugins are not supported. Please provide a single plugin value.
Test Result: PASS
TC3: Reject invalid provider names
Objective
Verify that setting backup.framework.provider.plugin to an invalid provider name is rejected with an appropriate error message listing the valid options, and verify behavior with case variations of valid names.
Test Steps
- Via CloudMonkey, attempt to set invalid provider names:
update configuration name=backup.framework.provider.plugin value=otherupdate configuration name=backup.framework.provider.plugin value=invalidupdate configuration name=backup.framework.provider.plugin value=veeam2
- In the UI, navigate to Configuration → Global Settings, set
backup.framework.provider.plugintootherand click save — observe the error - Via CloudMonkey, test case variations of valid names:
update configuration name=backup.framework.provider.plugin value=DUMMYupdate configuration name=backup.framework.provider.plugin value=Veeamupdate configuration name=backup.framework.provider.plugin value=NaSupdate configuration name=backup.framework.provider.plugin value=nAS
- Check management server logs:
grep -i "Invalid backup provider" /var/log/cloudstack/management/management-server.log | tail -5 - Check for runtime backup provider errors:
grep -i "Failed to find backup provider" /var/log/cloudstack/management/management-server.log | tail -5
Expected Result:
Invalid provider names should be rejected with error: "Invalid backup provider plugin: . Valid plugin values are: dummy, veeam, networker, nas". Case variations of valid names should either be rejected or normalized to lowercase before saving.
Actual Result:
All invalid provider names (other, invalid, veeam2) were correctly rejected with the expected error message both via API (HTTP 431, error code 9999) and via UI.
However, case variations of valid provider names (DUMMY, Veeam, NaS, nAS) were accepted and saved as-is (without normalizing to lowercase). This causes a runtime failure — the backupProvidersMap lookup in BackupManagerImpl.getBackupProvider() is case-sensitive, so a value like nAS passes validation but fails at runtime with: Failed to find backup provider by the name: nAS.
BUG: The validator uses .toLowerCase() to check validity but the value is stored in its original case. The runtime provider map lookup is case-sensitive. The fix should either:
- Reject non-lowercase values in the validator, OR
- Normalize the value to lowercase before storing it
Test Evidence:
CloudMonkey output — invalid values rejected:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=other
🙈 Error: (HTTP 431, error code 9999) Invalid backup provider plugin: other. Valid plugin values are: dummy, veeam, networker, nas
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=invalid
🙈 Error: (HTTP 431, error code 9999) Invalid backup provider plugin: invalid. Valid plugin values are: dummy, veeam, networker, nas
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=veeam2
🙈 Error: (HTTP 431, error code 9999) Invalid backup provider plugin: veeam2. Valid plugin values are: dummy, veeam, networker, nas
Case variations accepted (should not have been): DUMMY, Veeam, NaS, nAS — all saved successfully without error.
UI: Setting other in the Global Settings UI resulted in an error dialog: "Invalid backup provider plugin: other. Valid plugin values are: dummy, veeam, networker, nas"
Screencast.from.2026-02-06.12-31-19.webm
Management server log — invalid values rejected:
2026-02-06 10:29:23,422 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-a7998dda, ctx-2d139540, ctx-7365cbed]) (logid:c86be57f) Invalid backup provider plugin: other. Valid plugin values are: dummy, veeam, networker, nas
2026-02-06 10:29:28,660 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-f668f843, ctx-1f45af7a, ctx-73ea5470]) (logid:9282842d) Invalid backup provider plugin: invalid. Valid plugin values are: dummy, veeam, networker, nas
2026-02-06 10:29:30,157 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-7bd13b92, ctx-4c89683e, ctx-d3e84807]) (logid:4a304cea) Invalid backup provider plugin: veeam2. Valid plugin values are: dummy, veeam, networker, nas
2026-02-06 10:29:45,626 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-c175c52d, ctx-d5292846]) (logid:de7422c0) Invalid backup provider plugin: other. Valid plugin values are: dummy, veeam, networker, nas
2026-02-06 10:30:04,994 INFO [c.c.a.ApiServer] (qtp2038105753-23:[ctx-5d4c23e1, ctx-fdc786d3]) (logid:2cdd9dd8) Invalid backup provider plugin: other. Valid plugin values are: dummy, veeam, networker, nas
Runtime error from case-sensitive provider lookup (after nAS was set in TC3):
2026-02-06 10:32:59,600 ERROR [o.a.c.b.B.BackupSyncTask] (BackgroundTaskPollManager-6:[ctx-b9ae99bd]) (logid:7af270ee) Error trying to run backup-sync background task due to: [Failed to find backup provider by the name: nAS]. com.cloud.utils.exception.CloudRuntimeException: Failed to find backup provider by the name: nAS
Result: FAIL (case-insensitive validation allows values that cause runtime failures)
TC4: Accept valid single providers
Objective
Verify that each valid backup provider plugin value (dummy, veeam, networker, nas) can be successfully set via both API and UI.
Test Steps
- Via CloudMonkey, set each valid provider:
update configuration name=backup.framework.provider.plugin value=dummyupdate configuration name=backup.framework.provider.plugin value=veeamupdate configuration name=backup.framework.provider.plugin value=networkerupdate configuration name=backup.framework.provider.plugin value=nas
- Verify the current value:
list configurations name=backup.framework.provider.plugin - In the UI, navigate to Configuration → Global Settings, set
backup.framework.provider.plugintodummyand confirm it saves without error
Expected Result:
All four valid provider values should be accepted and saved successfully without any error, both via API and UI.
Actual Result:
All four valid provider values (dummy, veeam, networker, nas) were accepted and saved successfully via CloudMonkey. Each response returned the updated configuration with the correct value. The list configurations command confirmed the final value was set to dummy. The UI also saved the value without error.
Test Evidence:
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=dummy
{
"configuration": {
"category": "Advanced",
"component": "BackupService",
"defaultvalue": "dummy",
"description": "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas",
"displaytext": "Backup framework provider plugin",
"group": "Miscellaneous",
"isdynamic": true,
"name": "backup.framework.provider.plugin",
"parent": "backup.framework.enabled",
"subgroup": "Backup & Recovery",
"type": "String",
"value": "dummy"
}
}
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=veeam
{
"configuration": {
...
"value": "veeam"
}
}
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=networker
{
"configuration": {
...
"value": "networker"
}
}
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=nas
{
"configuration": {
...
"value": "nas"
}
}
(localcloud) 🐱 > list configurations name=backup.framework.provider.plugin
{
"configuration": [
{
"category": "Advanced",
"component": "BackupService",
"defaultvalue": "dummy",
"description": "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas",
"displaytext": "Backup framework provider plugin",
"group": "Miscellaneous",
"isdynamic": true,
"name": "backup.framework.provider.plugin",
"parent": "backup.framework.enabled",
"subgroup": "Backup & Recovery",
"type": "String",
"value": "dummy"
}
],
"count": 1
}
UI: Setting value to dummy via Global Settings saved successfully without error.
Screencast.from.2026-02-06.12-33-55.webm
Test Result: PASS
TC5: Accept null/empty handling
Objective
Verify behavior when setting backup.framework.provider.plugin to an empty value via API and UI.
Test Steps
- Via CloudMonkey, set an empty value:
update configuration name=backup.framework.provider.plugin value=
- In the UI, navigate to Configuration → Global Settings, clear the
backup.framework.provider.pluginfield and click save - Check management server logs:
grep -i "backup.framework.provider.plugin" /var/log/cloudstack/management/management-server.log | tail -5
Expected Result:
Empty value should either be rejected with a validation error or should reset to the default value (dummy).
Actual Result:
- Via CloudMonkey, the empty value was accepted and saved successfully — the configuration was set to
value: "". The validator did not catch this because the code checksvalue != nullbut an empty string is not null, so it passes through both the multiple-provider check and the valid-name check.
In the UI, clearing the field and saving resulted in the default valuedummybeing automatically placed back in the input field. - The management server log shows the range validation was skipped because the value was treated as null: "Not proceeding with configuration's range validation, as its provided value is null."
Test Evidence:
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=
{
"configuration": {
"category": "Advanced",
"component": "BackupService",
"defaultvalue": "dummy",
"description": "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas",
"displaytext": "Backup framework provider plugin",
"group": "Miscellaneous",
"isdynamic": true,
"name": "backup.framework.provider.plugin",
"parent": "backup.framework.enabled",
"subgroup": "Backup & Recovery",
"type": "String",
"value": ""
}
}
UI: Clearing the field and saving resulted in dummy being automatically restored in the input field.
Screencast.from.2026-02-06.12-35-20.webm
Management server log:
2026-02-06 10:35:23,779 WARN [c.c.c.ConfigurationManagerImpl] (qtp2038105753-22:[ctx-cdecebe9, ctx-c11ee58b]) (logid:c4504fef) Did not find configuration [backup.framework.provider.plugin] in Config.java. Perhaps moved to ConfigDepot.
2026-02-06 10:35:23,780 WARN [c.c.c.ConfigurationManagerImpl] (qtp2038105753-22:[ctx-cdecebe9, ctx-c11ee58b]) (logid:c4504fef) Did not find configuration [backup.framework.provider.plugin] in Config.java. Perhaps moved to ConfigDepot.
2026-02-06 10:35:23,780 DEBUG [c.c.c.ConfigurationManagerImpl] (qtp2038105753-22:[ctx-cdecebe9, ctx-c11ee58b]) (logid:c4504fef) Not proceeding with configuration [backup.framework.provider.plugin]'s range validation, as its provided value is null.
2026-02-06 10:35:23,790 WARN [c.c.c.ConfigurationManagerImpl] (qtp2038105753-22:[ctx-cdecebe9, ctx-c11ee58b]) (logid:c4504fef) Did not find configuration [backup.framework.provider.plugin] in Config.java. Perhaps moved to ConfigDepot.
2026-02-06 10:35:23,791 DEBUG [c.c.a.ApiServlet] (qtp2038105753-22:[ctx-cdecebe9, ctx-c11ee58b]) (logid:c4504fef) ===END=== 10.0.3.251 -- GET name=backup.framework.provider.plugin&value=&command=updateConfiguration&response=json&sessionkey=9WULZifyoB7OwDN8hK-HzRNkjNI
Note: The API accepts an empty string value because the validator checks value != null but does not check for empty/blank strings. This could be flagged as a minor improvement — the validator could additionally reject empty or blank values.
Result: PASS (with minor API observation)
TC6: Capacity dashboard loads correctly with valid provider
Objective
Verify that the Capacity dashboard loads fully and displays all stats when a valid single backup provider is configured.
Test Steps
- Set provider to valid value:
update configuration name=backup.framework.provider.plugin value=dummy - Confirm the value:
list configurations name=backup.framework.provider.plugin - Navigate to the Dashboard in the CloudStack UI and verify all capacity sections load
- Check CapacityChecker logs:
grep -i "CapacityChecker" /var/log/cloudstack/management/management-server.log | tail -10 - Check for backup provider errors:
grep -i "Failed to find backup provider" /var/log/cloudstack/management/management-server.log | tail -5
Expected Result:
Dashboard should display all sections fully — Infrastructure, Compute (Memory, CPU, CPU cores, GPU), Storage, Network, Alerts, Events. No CapacityChecker exceptions in the logs.
Actual Result:
Dashboard loaded fully with all capacity sections displaying correctly: Memory (11.11%, 1.50 GiB / 13.50 GiB), CPU (3.97%, 1.00 GHz / 25.20 GHz), CPU cores (33.33%, 2/6), GPU (0%), Storage (55.36%), Network (VLAN/VNI, Public IPs, Management IPs). Infrastructure, Alerts, and Events sections all populated. CapacityChecker logs show successful execution with no exceptions.
One observation: the backup provider error log shows Failed to find backup provider by the name: nAS - this is a residual error from TC3 where the case variation nAS was accepted by the validator but rejected at runtime by the provider lookup (backupProvidersMap). This indicates a mismatch: the validator uses .toLowerCase() to accept case-insensitive values, but the provider map lookup is case-sensitive. This should be flagged as a bug in the PR review.
Test Evidence:
Dashboard : All sections loaded - Infrastructure (1 Pod, 1 Cluster, 2 Hosts, 0 Alerts, 2 Primary Storage, 2 System VMs, 0 Virtual Routers, 0 Instances), Compute capacity (Memory, CPU, CPU cores, GPU), Storage capacity (Primary used, Primary allocated, Secondary), Network (VLAN/VNI, Public IPs, Management IPs), Alerts, and Events all fully visible.
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=dummy
{
"configuration": {
...
"value": "dummy"
}
}
(localcloud) 🐱 > list configurations name=backup.framework.provider.plugin
{
"configuration": [
{
...
"value": "dummy"
}
],
"count": 1
}
CapacityChecker log (no errors):
2026-02-06 10:33:23,280 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Executing cpu/ram capacity update
2026-02-06 10:33:23,299 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Done executing cpu/ram capacity update
2026-02-06 10:33:23,299 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Executing storage capacity update
2026-02-06 10:33:23,311 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Done executing storage capacity update
2026-02-06 10:33:23,311 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Executing capacity updates for public ip and Vlans
2026-02-06 10:33:23,317 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Done capacity updates for public ip and Vlans
2026-02-06 10:33:23,317 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Executing capacity updates for private ip
2026-02-06 10:33:23,320 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Done executing capacity updates for private ip
2026-02-06 10:33:23,320 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Done recalculating system capacity
2026-02-06 10:33:23,335 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-d5751819]) (logid:d7b911cd) Done running Capacity Checker ...
Backup provider error log (residual from TC3 case-sensitivity test):
2026-02-06 10:32:59,600 ERROR [o.a.c.b.B.BackupSyncTask] (BackgroundTaskPollManager-6:[ctx-b9ae99bd]) (logid:7af270ee) Error trying to run backup-sync background task due to: [Failed to find backup provider by the name: nAS]. com.cloud.utils.exception.CloudRuntimeException: Failed to find backup provider by the name: nAS
Result: PASS
TC7: Capacity dashboard after MS restart
Objective
Verify that the Capacity dashboard loads correctly after a management server restart with a valid backup provider configured.
Test Steps
- Confirm
backup.framework.provider.pluginis set todummy - Restart the management server:
systemctl restart cloudstack-management - Wait for the management server to come back up
- Navigate to the Dashboard in the CloudStack UI and verify all capacity sections load
- Check CapacityChecker logs:
grep -i "CapacityChecker" /var/log/cloudstack/management/management-server.log | tail -10 - Check for backup provider errors:
grep -i "Failed to find backup provider" /var/log/cloudstack/management/management-server.log | tail -5
Expected Result:
After management server restart, the dashboard should load fully with all capacity sections displayed. No new CapacityChecker exceptions or backup provider errors in the logs.
Actual Result:
Dashboard loaded fully after MS restart with all sections displaying correctly: Memory (11.11%, 1.50 GiB / 13.50 GiB), CPU (3.97%, 1.00 GHz / 25.20 GHz), CPU cores (33.33%, 2/6), GPU (0%), Storage (Primary used 54.99%, Primary allocated 0.00%, Secondary 54.99%), Network (VLAN/VNI, Public IPs, Management IPs), Alerts, and Events. CapacityChecker logs show successful execution with no exceptions after restart. The only "Failed to find backup provider" error in the logs is from 10:32 (pre-restart, residual from TC3), with no new occurrences after the restart at 11:33.
Test Evidence:
Dashboard: All sections loaded correctly after MS restart — Infrastructure (1 Pod, 1 Cluster, 2 Hosts, 0 Alerts, 2 Primary Storage, 2 System VMs, 0 Virtual Routers, 0 Instances), Compute capacity, Storage capacity, Network, Alerts (showing "Management server node 10.0.34.75 is up" at 06 Feb 2026 11:33:16 confirming fresh restart), and Events.
CapacityChecker log (post-restart, no errors):
2026-02-06 11:33:43,240 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Executing cpu/ram capacity update
2026-02-06 11:33:43,268 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Done executing cpu/ram capacity update
2026-02-06 11:33:43,268 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Executing storage capacity update
2026-02-06 11:33:43,297 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Done executing storage capacity update
2026-02-06 11:33:43,297 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Executing capacity updates for public ip and Vlans
2026-02-06 11:33:43,310 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Done capacity updates for public ip and Vlans
2026-02-06 11:33:43,310 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Executing capacity updates for private ip
2026-02-06 11:33:43,314 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Done executing capacity updates for private ip
2026-02-06 11:33:43,314 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Done recalculating system capacity
2026-02-06 11:33:43,345 DEBUG [c.c.a.AlertManagerImpl] (CapacityChecker:[ctx-df4c02f9]) (logid:398dd079) Done running Capacity Checker ...
Backup provider error log (only pre-restart residual from TC3, no new errors):
2026-02-06 10:32:59,600 ERROR [o.a.c.b.B.BackupSyncTask] (BackgroundTaskPollManager-6:[ctx-b9ae99bd]) (logid:7af270ee) Error trying to run backup-sync background task due to: [Failed to find backup provider by the name: nAS]. com.cloud.utils.exception.CloudRuntimeException: Failed to find backup provider by the name: nAS
Test Result: PASS
TC9: Zone-scoped setting
Objective
Verify that the backup provider plugin validation works correctly when setting the configuration at zone scope, accepting valid values and rejecting invalid and multiple provider values.
Test Steps
- Get the zone ID:
list zones - Set a valid provider at zone scope:
update configuration name=backup.framework.provider.plugin value=nas zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
- Attempt to set comma-separated providers at zone scope:
update configuration name=backup.framework.provider.plugin value=dummy,nas zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
- Attempt to set an invalid provider at zone scope:
update configuration name=backup.framework.provider.plugin value=invalid zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
- Verify the zone-level value:
list configurations name=backup.framework.provider.plugin zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
Expected Result:
Valid single provider should be accepted at zone scope. Multiple providers and invalid provider names should be rejected with the same error messages as global scope.
Actual Result:
Valid provider nas was accepted at zone scope and saved successfully with scope: zone. Comma-separated value dummy,nas was rejected with "Multiple backup provider plugins are not supported." Invalid value invalid was rejected with "Invalid backup provider plugin: invalid." The list configurations with zone ID confirmed the value was set to nas at zone scope. All validation behaves identically at zone scope as at global scope.
Test Evidence:
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=nas zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
{
"configuration": {
"category": "Advanced",
"component": "BackupService",
"defaultvalue": "dummy",
"description": "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas",
"displaytext": "Backup framework provider plugin",
"group": "Miscellaneous",
"isdynamic": true,
"name": "backup.framework.provider.plugin",
"parent": "backup.framework.enabled",
"scope": "zone",
"subgroup": "Backup & Recovery",
"type": "String",
"value": "nas"
}
}
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=dummy,nas zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
🙈 Error: (HTTP 431, error code 9999) Multiple backup provider plugins are not supported. Please provide a single plugin value.
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=invalid zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
🙈 Error: (HTTP 431, error code 9999) Invalid backup provider plugin: invalid. Valid plugin values are: dummy, veeam, networker, nas
(localcloud) 🐱 > list configurations name=backup.framework.provider.plugin zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
{
"configuration": [
{
...
"scope": "zone",
"value": "nas"
}
],
"count": 1
}
Test Result: PASS
TC10: Verify BackupManagerImpl indentation fix
Objective
Verify that the whitespace-only change in BackupManagerImpl.getBackupProvider() did not break the backup provider lookup functionality.
Test Steps
- Set provider to
dummyat zone scope:update configuration name=backup.framework.provider.plugin value=dummy zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
- Execute a backup-related API call that triggers provider lookup:
list backupofferings zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
- Check for any new backup provider errors:
grep -i "Failed to find backup provider" /var/log/cloudstack/management/management-server.log | grep "$(date +%Y-%m-%d)" | grep -v "nAS" | tail -5
Expected Result:
Backup provider lookup should work without errors. Backup-related API calls should execute successfully (returning results or empty set, but no exceptions).
Actual Result:
The provider was set to dummy successfully. The list backupofferings command returned an empty set (no offerings configured) but executed without errors, confirming the provider lookup in getBackupProvider() worked correctly. No new "Failed to find backup provider" errors were found in the logs (excluding the pre-existing nAS error from TC3).
Test Evidence:
CloudMonkey output:
(localcloud) 🐱 > update configuration name=backup.framework.provider.plugin value=dummy zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
{
"configuration": {
"category": "Advanced",
"component": "BackupService",
"defaultvalue": "dummy",
"description": "The backup and recovery provider plugin. Valid plugin values: dummy, veeam, networker and nas",
"displaytext": "Backup framework provider plugin",
"group": "Miscellaneous",
"isdynamic": true,
"name": "backup.framework.provider.plugin",
"parent": "backup.framework.enabled",
"scope": "zone",
"subgroup": "Backup & Recovery",
"type": "String",
"value": "dummy"
}
}
(localcloud) 🐱 > list backupofferings zoneid=75df9f33-2957-48ef-aea2-ee0c258a687d
(empty result — no offerings configured, no errors)
Log check (no new backup provider errors):
[root@ref-trl-10868-k-Mol9-rositsa-kyuchukova-mgmt1 ~]# grep -i "Failed to find backup provider" /var/log/cloudstack/management/management-server.log | grep "$(date +%Y-%m-%d)" | grep -v "nAS" | tail -5
(no output — no new errors)
Test Result: PASS
|




Description
This PR fixed: #12449
The capacity dashboard issue is seen on 4.22 - but in general the getBackupProvider() is fixed to return the first provider set in the global settings when a comma separated list of providers is set.
94ac3ea - adds a validator, that prevents adding a comma separated list for backup provider setting. It also checks if the entered value is a valid one.
Types of changes
Feature/Enhancement Scale or Bug Severity
Feature/Enhancement Scale
Bug Severity
Screenshots (if appropriate):
How Has This Been Tested?
How did you try to break this feature and the system with this change?