Everpure: report the backend as an explicit single pool

The scheduler only emits capacity.pool and capacity.backend
notifications for backends whose statistics include a pools list,
and skips any pool lacking its required keys
(HostManager._get_updated_pools). The Everpure driver reported no
pools list, relying on the implicit pool the scheduler builds for
such drivers, so those notifications, and the
volume.provider.pool.capacity meters Ceilometer derives from them,
were never produced for a FlashArray backend. The earlier release
note for the provisioned_capacity_gb fix claimed to have restored
capacity telemetry; it restored the scheduler's over-subscription
accounting only, because the missing pools list is checked first.

A FlashArray has one tier of storage, so the backend is its only
pool. Report it as a one-element pools list carrying every existing
statistic, named after volume_backend_name. That is the name the
scheduler already gave the implicit pool, so the host#pool of
existing volumes and the capabilities.<key> names used in
filter_function and goodness_function expressions are unchanged.
thick_provisioning_support is now reported as False, which the
scheduler previously defaulted.

The unit test now also checks that the published pool passes the
scheduler's notification gate.

Assisted-By: Claude Code claude-fable-5-1
Change-Id: I897cc1d27e999ac6a7d0086449bb8a08fa0f9aec
Signed-off-by: Simon Dodsley <simon@purestorage.com>
This commit is contained in:
Simon Dodsley committed 2026-09-30 15:34:48 +01:00
1 parent 803dca69e6
commit 83c78c82d5
4 files changed
+54 -6

No files matched your search

+22 -5
View File
@@ -28,6 +28,7 @@ from cinder import exception
from cinder.objects import fields
from cinder.objects import volume_attachment
from cinder.objects import volume_type
from cinder.scheduler import host_manager
from cinder.tests.unit.consistencygroup import fake_cgsnapshot
from cinder.tests.unit import fake_constants as fake
from cinder.tests.unit import fake_group
@@ -6579,15 +6580,13 @@ class PureVolumeUpdateStatsTestCase(PureBaseSharedDriverTestCase):
mock_get_replication_capability.return_value = 'sync'
mock_get_thin_provisioning.return_value = TOTAL_REDUCTION
expected_result = {
'volume_backend_name': VOLUME_BACKEND_NAME,
'vendor_name': 'Pure Storage',
'driver_version': self.driver.VERSION,
'storage_protocol': None,
expected_pool = {
'pool_name': VOLUME_BACKEND_NAME,
'consistencygroup_support': True,
'consistent_group_snapshot_enabled': True,
'consistent_group_replication_enabled': True,
'thin_provisioning_support': True,
'thick_provisioning_support': False,
'multiattach': True,
'QoS_support': True,
'total_capacity_gb': TOTAL_CAPACITY,
@@ -6619,8 +6618,26 @@ class PureVolumeUpdateStatsTestCase(PureBaseSharedDriverTestCase):
'replication_count': 0,
'replication_targets': [],
}
expected_result = {
'volume_backend_name': VOLUME_BACKEND_NAME,
'vendor_name': 'Pure Storage',
'driver_version': self.driver.VERSION,
'storage_protocol': None,
'pools': [expected_pool],
}
real_result = self.driver.get_volume_stats(refresh=True)
self.assertDictEqual(expected_result, real_result)
# The single pool carries every key the scheduler requires before
# it will emit capacity notifications for the backend, except
# allocated_capacity_gb which the volume manager adds per pool.
required = (host_manager.HostManager.REQUIRED_KEYS -
{'allocated_capacity_gb'})
self.assertTrue(required.issubset(real_result['pools'][0]))
published = deepcopy(real_result)
published['pools'][0]['allocated_capacity_gb'] = 0
self.assertEqual(
published['pools'],
host_manager.HostManager()._get_updated_pools({}, published))
# Make sure when refresh=False we are using cached values and not
# sending additional requests to the array.
+18 -1
View File
@@ -1682,7 +1682,24 @@ class PureBaseVolumeDriver(san.SanDriver):
data["replication_count"] = len(self._replication_target_arrays)
data["replication_targets"] = [array.backend_id for array
in self._replication_target_arrays]
self._stats = data
# A FlashArray has a single tier of storage, so the backend is its
# only pool. Report it as an explicit one-element pools list: the
# scheduler only emits capacity.pool and capacity.backend
# notifications for backends that report pools, and it skips a
# pool that lacks any of its required keys. The pool is named after
# the backend, which is the name the scheduler gave the implicit
# pool before, so host#pool strings of existing volumes and the
# capabilities.<key> names used in filter and goodness functions
# are unchanged.
backend_keys = ('volume_backend_name', 'vendor_name',
'driver_version', 'storage_protocol')
pool = {key: value for key, value in data.items()
if key not in backend_keys}
pool['pool_name'] = self._backend_name
pool['thick_provisioning_support'] = False
self._stats = {key: data[key] for key in backend_keys}
self._stats['pools'] = [pool]
def _get_replication_capability(self):
"""Discovered connected arrays status for replication"""
@@ -385,6 +385,11 @@ A large number of metrics are reported by the volume driver which can be useful
in implementing more control over volume placement in multi-backend
environments using the driver filter and weighter methods.
A FlashArray has a single tier of storage, so the driver reports the whole
backend as one pool named after ``volume_backend_name``. Volumes are placed on
``<host>@<backend>#<volume_backend_name>``, and the scheduler emits its
``capacity.pool`` and ``capacity.backend`` notifications for that pool.
Performance metrics are provided based on an average over the previous
30 seconds.
@@ -0,0 +1,9 @@
---
fixes:
- |
Everpure driver: The backend is now reported to the scheduler as a
single pool named after ``volume_backend_name``. The scheduler only
emits ``capacity.pool`` and ``capacity.backend`` notifications for
backends that report a pools list, so capacity telemetry had never been
produced for FlashArray backends. Existing ``host#pool`` values and
``capabilities.<metric>`` references are unchanged.