pFad - Phone/Frame/Anonymizer/Declutterfier! Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

URL: http://github.com/apache/cloudstack/pull/13050

ps://github.githubassets.com/assets/actions-0e714a98ea09295a.css" /> flasharray: fall back to array capacity when pod has no quota by genegr · Pull Request #13050 · apache/cloudstack · GitHub
Skip to content

flasharray: fall back to array capacity when pod has no quota#13050

Open
genegr wants to merge 1 commit intoapache:4.22from
genegr:fix/flasharray-managed-stats-array-capacity-fallback
Open

flasharray: fall back to array capacity when pod has no quota#13050
genegr wants to merge 1 commit intoapache:4.22from
genegr:fix/flasharray-managed-stats-array-capacity-fallback

Conversation

@genegr
Copy link
Copy Markdown

@genegr genegr commented Apr 20, 2026

Description

This PR fixes FlashArrayAdapter.getManagedStorageStats() so that a FlashArray primary pool registered against a pod without an explicit quota reports real capacity to the CloudStack allocator instead of 0 / 0.

Problem

getManagedStorageStats() returns null whenever the pod footprint is 0, and otherwise derives capacity purely from the pod quota:

if (pod == null || pod.getFootprint() == 0) {
    return null;
}
Long capacityBytes = pod.getQuotaLimit();
Long usedBytes     = pod.getQuotaLimit() - (pod.getQuotaLimit() - pod.getFootprint());

A freshly-registered pool on a pod without a quota therefore surfaces as:

disksizetotal = 0
disksizeused  = 0

ClusterScopeStoragePoolAllocator treats a zero-capacity pool as ineligible and skips it. The user's first attempt to deploy onto the pool fails with Unable to find suitable primary storage, and there is no documented way to fix it from the CloudStack side — the operator has to discover that pod quotas drive the reported capacity and set one on the array by hand.

The secondary bug is the usedBytes math: pod.getQuotaLimit() - (pod.getQuotaLimit() - pod.getFootprint()) is just pod.getFootprint(), but with an extra NullPointerException surface when getQuotaLimit() returns null.

Fix

  • Report pod.getQuotaLimit() when present and non-zero; otherwise fall back to the array's total physical capacity via GET /arrays?space=true (a new getArrayTotalCapacity() helper).
  • Only return null when neither value is obtainable (i.e. the array REST is unreachable) — not when the pod is simply empty.
  • Report pod.getFootprint() as usedBytes, defaulting to 0 when the field is absent. Drops the NPE-prone math.

Expected behaviour: cmk list storagepools name=<pool> shows a non-zero disksizetotal (the pod quota if set, or the array total otherwise); subsequent deploys route to the pool normally.
Actual behaviour (before this PR): disksizetotal=0, the allocator skips the pool, deploys fail with Unable to find suitable primary storage, operator has to manually set a pod quota on the array.

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

A freshly-registered pool is unusable for allocation until the operator discovers the undocumented pod-quota requirement and sets it by hand on the array. Not a BLOCKER (the pool still builds up; create-from-API with an explicit pool id still works), but any default-offering-based deploy hits it.

Screenshots (if appropriate):

N/A — backend adapter change, no UI surface.

How Has This Been Tested?

Tested against Purity 6.7 on a two-node KVM cluster with a FlashArray pool registered against a pod that has no quota set.

  1. Register pool via cmk create storagepool ... provider=FlashArray url=https://<user>:<pass>@<fa>:443/api?pod=<name>&api_skiptlsvalidation=true.
  2. cmk list storagepools name=<pool> — verified disksizetotal == array total physical capacity (matches GET /arrays?space=truecapacity = 29.5 TB on the test array).
  3. cmk deploy virtualmachine ... using an offering tagged to the pool — succeeds.
  4. cmk create volume + cmk attach volume — succeeds; disksizeused increments by the provisioned size.
  5. Repeated with a pod that does have an explicit quota — verified the quota is reported instead of the array total (no behaviour change for that path).

Build: mvn -pl plugins/storage/volume/flasharray --also-make -am -DskipTests -Dcheckstyle.skip=false --batch-mode package passes with checkstyle enabled.

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

  • Array unreachable during a stats refresh: getArrayTotalCapacity() catches the exception, logs a warning, returns null; the outer method then returns null and the allocator treats the pool as temporarily unavailable — same behaviour as any other transient storage-pool-stats failure. No crash, no NPE.
  • Pod exists but REST returns no quota field: pod.getQuotaLimit() is null → falls through to the array-total path → pool still reports real capacity.
  • Pod footprint absent: usedBytes defaults to 0. Verified with SELECT disksizeused FROM storage_pool WHERE name=... before any volume has been provisioned.
  • Array capacity field is non-numeric (defensive, not seen in practice): cap instanceof Number guards the cast; falls through to null without throwing.
  • Pod with explicit quota smaller than current footprint: still reports the quota (not clamped) — matches prior behaviour, not changed by this PR.

FlashArrayAdapter.getManagedStorageStats() returns null whenever the
backing pod has no volumes (footprint == 0) and never reports anything
other than the pod quota otherwise. A freshly-registered pool that sits
on a pod without an explicit quota therefore shows

    disksizetotal=0, disksizeused=0

and the ClusterScopeStoragePoolAllocator refuses to allocate any volume
against it (zero-capacity pool is skipped). The plugin is unusable
until a pod quota is set manually on the array - which is not documented
anywhere and not discoverable from the CloudStack side.

Fix: fall back to the arrays total physical capacity (retrieved via
GET /arrays?space=true) when the pod has no quota, or when the quota
is zero. The used value falls back to the pod footprint, defaulting to
0 when absent. Only return null when no capacity value is obtainable at
all, which now only happens if the array itself is unreachable.

The math for usedBytes was also simplified: the previous form

    pod.getQuotaLimit() - (pod.getQuotaLimit() - pod.getFootprint())

is just pod.getFootprint() with an extra NPE risk when getQuotaLimit()
is null.
FlashArrayList<Map<String, Object>> list = GET("/arrays?space=true",
new TypeReference<FlashArrayList<Map<String, Object>>>() {
});
if (list != null && list.getItems() != null && !list.getItems().isEmpty()) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (list != null && list.getItems() != null && !list.getItems().isEmpty()) {
if (list != null && CollectionUtils.isNotEmpty(list.getItems())) {

@sureshanaparti
Copy link
Copy Markdown
Contributor

@blueorangutan package

@blueorangutan
Copy link
Copy Markdown

@sureshanaparti 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.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 21, 2026

Codecov Report

❌ Patch coverage is 0% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 17.68%. Comparing base (be89e6f) to head (ee38a87).

Files with missing lines Patch % Lines
...atastore/adapter/flasharray/FlashArrayAdapter.java 0.00% 18 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               4.22   #13050      +/-   ##
============================================
- Coverage     17.68%   17.68%   -0.01%     
  Complexity    15793    15793              
============================================
  Files          5922     5922              
  Lines        533096   533112      +16     
  Branches      65209    65214       +5     
============================================
  Hits          94275    94275              
- Misses       428181   428197      +16     
  Partials      10640    10640              
Flag Coverage Δ
uitests 3.69% <ø> (ø)
unittests 18.76% <0.00%> (-0.01%) ⬇️

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.

@blueorangutan
Copy link
Copy Markdown

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

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.

3 participants

pFad - Phonifier reborn

Pfad - The Proxy pFad © 2024 Your Company Name. All rights reserved.





Check this box to remove all script contents from the fetched content.



Check this box to remove all images from the fetched content.


Check this box to remove all CSS styles from the fetched content.


Check this box to keep images inefficiently compressed and original size.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy