)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[],"source_content_type":"","patch_set":1,"id":"16033695_7647404d","updated":"2026-06-25 13:39:10.000000000","message":"Two blocking items: the \"incomplete blocking\" justification is backwards (service-disable already blocks extend/snapshot/retype today), and the pool-name key diverges from what the filter actually matches under active/active. \nFour smaller items as well. \nThe filter is more comprehensive than the spec claims — migrate, manage_existing, and group-create all funnel through backend_passes_filters, so they\u0027re covered too; worth stating explicitly.\nAlso this should be moved to 2026.2 now","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"}],"specs/2026.1/pool-disable-draining.rst":[{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":34,"context_line":"  and health reporting, as a disabled service appears unhealthy even though"},{"line_number":35,"context_line":"  it is still running normally."},{"line_number":36,"context_line":""},{"line_number":37,"context_line":"* **Incomplete blocking**: Disabling a service only prevents the scheduler from"},{"line_number":38,"context_line":"  selecting that service as a *destination* for new volume creates. It does"},{"line_number":39,"context_line":"  **not** block extend, snapshot, or retype operations on volumes already"},{"line_number":40,"context_line":"  residing on that service, since those operations validate the existing backend"}],"source_content_type":"text/x-rst","patch_set":1,"id":"85bd7c58_daddd5df","line":37,"range":{"start_line":37,"start_character":2,"end_line":37,"end_character":25},"updated":"2026-06-25 13:39:10.000000000","message":"This is backwards against master. host_manager._update_backend_state_map builds the state map from ServiceList.get_all(context, {\u0027topic\u0027: topic, \u0027disabled\u0027: False, \u0027frozen\u0027: False}), so a disabled service\u0027s backends are dropped from the map entirely. backend_passes_filters then raises NoValidBackend for extend/snapshot/retype/migrate on volumes residing there — i.e. service-disable already blocks all of those today, not just new-create destination selection. Please drop this justification and lean on the two valid ones: granularity (one service disables all its pools) and the health/semantic conflation of the service disabled flag.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":109,"context_line":"* **Volume extend**: Same as snapshot -- the scheduler validates the existing"},{"line_number":110,"context_line":"  pool via ``backend_passes_filters()``. The filter rejects it. An API-level"},{"line_number":111,"context_line":"  pre-check also returns HTTP 409 immediately."},{"line_number":112,"context_line":""},{"line_number":113,"context_line":"* **Retype**: The scheduler runs the full filter/weigh pipeline. If the"},{"line_number":114,"context_line":"  volume\u0027s current pool is disabled:"},{"line_number":115,"context_line":""}],"source_content_type":"text/x-rst","patch_set":1,"id":"e26240cb_941a8a69","line":112,"updated":"2026-06-25 13:39:10.000000000","message":"Worth noting the filter coverage is broader than listed here: scheduler/manager.py routes migrate_volume, manage_existing, manage_existing_snapshot, and group validate_host_capacity all through backend_passes_filters, so a disabled pool is also blocked as a migrate destination and for manage/group-create. Recommend listing these so reviewers don\u0027t assume they\u0027re gaps. (Draining off a disabled pool still works — backend_passes_filters runs against the destination, not the source.)","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":179,"context_line":"A new table ``pool_disabled_states`` is introduced:"},{"line_number":180,"context_line":""},{"line_number":181,"context_line":".. code-block:: sql"},{"line_number":182,"context_line":""},{"line_number":183,"context_line":"    CREATE TABLE pool_disabled_states ("},{"line_number":184,"context_line":"        id              INTEGER PRIMARY KEY AUTOINCREMENT,"},{"line_number":185,"context_line":"        pool_name       VARCHAR(255) NOT NULL UNIQUE,"}],"source_content_type":"text/x-rst","patch_set":1,"id":"88b99453_8c78a9b4","line":182,"updated":"2026-06-25 13:39:10.000000000","message":"The illustrative DDL is SQLite-flavored (AUTOINCREMENT); the real migration should follow Cinder\u0027s SQLAlchemy/alembic soft-delete conventions. Also, UNIQUE(pool_name) is what forces the restore-the-soft-deleted-row dance on re-disable and erases the audit trail of repeated disable events — consider UNIQUE(pool_name, deleted) instead.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":248,"context_line":""},{"line_number":249,"context_line":"    GET /scheduler-stats/get_pools?name\u003dhost%40backend%23pool2\u0026detail\u003dtrue"},{"line_number":250,"context_line":""},{"line_number":251,"context_line":"**2. New endpoint: PUT /pool-states/down**"},{"line_number":252,"context_line":""},{"line_number":253,"context_line":"Mark a pool as disabled. Admin-only."},{"line_number":254,"context_line":""}],"source_content_type":"text/x-rst","patch_set":1,"id":"b415b72b_e2c9b216","line":251,"updated":"2026-06-25 13:39:10.000000000","message":"up/down is exactly the service-state vocabulary you\u0027re trying to disentangle from admin state, and the References section already cites PUT /clusters/disable as the precedent — match it with /disable and /enable. Separately, there\u0027s no GET on /pool-states: state is written here but read back from scheduler-stats/get_pools. A read endpoint, or folding this into a coherent /pools resource, would be cleaner than splitting write and read across two surfaces.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":321,"context_line":"Security impact"},{"line_number":322,"context_line":"---------------"},{"line_number":323,"context_line":""},{"line_number":324,"context_line":"No new security concerns. The new API endpoints use the existing"},{"line_number":325,"context_line":"``RULE_ADMIN_API`` policy, restricting access to cloud administrators only."},{"line_number":326,"context_line":"The disable reason is a free-form string limited to 255 characters."},{"line_number":327,"context_line":""},{"line_number":328,"context_line":""},{"line_number":329,"context_line":"Active/Active HA impact"}],"source_content_type":"text/x-rst","patch_set":1,"id":"706a973a_83f86684","line":326,"range":{"start_line":324,"start_character":0,"end_line":326,"end_character":67},"updated":"2026-06-25 13:39:10.000000000","message":"Define an explicit policy module under cinder/policies/ (with registered rule names and defaults) rather than inlining RULE_ADMIN_API. That\u0027s the current convention for new admin APIs and lets operators override the rules without code changes.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":326,"context_line":"The disable reason is a free-form string limited to 255 characters."},{"line_number":327,"context_line":""},{"line_number":328,"context_line":""},{"line_number":329,"context_line":"Active/Active HA impact"},{"line_number":330,"context_line":"-----------------------"},{"line_number":331,"context_line":""},{"line_number":332,"context_line":"The disabled pool state is stored in the database, which is shared across all"}],"source_content_type":"text/x-rst","patch_set":1,"id":"07a0725a_712604aa","line":329,"range":{"start_line":329,"start_character":0,"end_line":329,"end_character":23},"updated":"2026-06-25 13:39:10.000000000","message":"The state-key naming won\u0027t match what the filter evaluates under A/A. get_pools (what the admin sees and what this API validates against) builds the name via append_host(backend_key, pool_name) with backend_key \u003d service.service_topic_queue → cluster@backend#pool. But the candidate the filter sees is a PoolState whose .host is append_host(service.host, pool_name) → host@backend#pool. These coincide only when service_topic_queue \u003d\u003d host (non-clustered); in A/A they diverge, so a row keyed on the get_pools name won\u0027t match the filter\u0027s candidate. Please canonicalize on the service_topic_queue-based name and state it explicitly, plus define behavior for rows orphaned by a backend/pool rename.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":386,"context_line":"---------------------"},{"line_number":387,"context_line":""},{"line_number":388,"context_line":"* The ``PoolDisabledFilter`` is added to ``scheduler_default_filters``. On"},{"line_number":389,"context_line":"  upgrade, the filter is active by default. Since the ``pool_disabled_states``"},{"line_number":390,"context_line":"  table starts empty, no pools are affected until an admin explicitly marks"},{"line_number":391,"context_line":"  one as disabled."},{"line_number":392,"context_line":""}],"source_content_type":"text/x-rst","patch_set":1,"id":"73625c1a_66e35266","line":389,"range":{"start_line":389,"start_character":25,"end_line":389,"end_character":42},"updated":"2026-06-25 13:39:10.000000000","message":"\"Active by default\" only holds for deployments using the default scheduler_default_filters ([\u0027AvailabilityZoneFilter\u0027, \u0027CapacityFilter\u0027, \u0027CapabilitiesFilter\u0027]). Operators who override that list won\u0027t get PoolDisabledFilter and won\u0027t enforce disable on creates unless they add it manually. Please call this out.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"},{"author":{"_account_id":13425,"name":"Simon Dodsley","email":"simon@purestorage.com","username":"sdodsley"},"change_message_id":"316e83c13a13aee0cc55f639e894391c0ed38449","unresolved":true,"context_lines":[{"line_number":418,"context_line":"* Add database migration for ``pool_disabled_states`` table"},{"line_number":419,"context_line":"* Create ``PoolDisabledState`` Oslo Versioned Object and DB API methods"},{"line_number":420,"context_line":"* Implement ``PoolDisabledFilter`` scheduler filter"},{"line_number":421,"context_line":"* Register filter in ``pyproject.toml`` entry points"},{"line_number":422,"context_line":"* Add filter to ``scheduler_default_filters``"},{"line_number":423,"context_line":"* Create ``/pool-states`` API controller, schema, view builder, and policy"},{"line_number":424,"context_line":"* Register routes in ``cinder/api/v3/router.py``"}],"source_content_type":"text/x-rst","patch_set":1,"id":"46b78a27_41ff3df2","line":421,"range":{"start_line":421,"start_character":2,"end_line":421,"end_character":52},"updated":"2026-06-25 13:39:10.000000000","message":"Filters aren\u0027t entry-point registered. HostManager discovers them via BackendFilterHandler(\u0027cinder.scheduler.filters\u0027).get_all_classes() and selects by cls.__name__ in _choose_backend_filters. The filter just needs to live under cinder/scheduler/filters/ and be named in the default list — drop this work item.","commit_id":"faec9e23cf9923def9d312512b434292658fe0e5"}]}
