From: Afreen Misbah Date: Mon, 9 Mar 2026 10:23:54 +0000 (+0530) Subject: mgr/dashboard: Fix scrubbing state X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=5cf596b9305ef4e47b24de8a794c6d503da386e3;p=ceph.git mgr/dashboard: Fix scrubbing state Fixes https://tracker.ceph.com/issues/75401 - not shown correct title "data cleanup in progress" - when all okay, scrubbing state percent not shown - - adds "unknown" state to PG_STATES Signed-off-by: Afreen Misbah --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/health-card/overview-health-card.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/health-card/overview-health-card.component.html index 3b02bf92443..e2213a77ed5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/health-card/overview-health-card.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/overview/health-card/overview-health-card.component.html @@ -292,7 +292,7 @@

- {{vm?.pgs?.activeCleanChartSeverity === 'progress' ? 'Data cleanup in progress' : 'What is affecting resiliency?'}} + {{vm?.resiliencyHealth?.severity === 'progress' ? 'Data cleanup in progress' : 'What is affecting resiliency?'}}

@for (item of vm?.pgs?.activeCleanChartReason; track item.state; let isLast =$last) { @if(item.count) { @@ -301,7 +301,7 @@ class="cds-mb-2"> {{item?.state}}: {{item.count}} % - @if(!item?.state?.includes('Scrub') || item?.state !== 'remapped') { + @if(!item?.state?.includes('Scrub') && item?.state !== 'Remapped') { }

diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/overview.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/overview.ts index cb8b40595d8..73a414e3086 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/overview.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/overview.ts @@ -14,6 +14,8 @@ type ResiliencyState = typeof DATA_RESILIENCY_STATE[keyof typeof DATA_RESILIENCY type PG_STATES = typeof PG_STATES[number]; +type SCRUBBING_STATES = typeof SCRUBBING_STATES[number]; + export const HealthIconMap = { HEALTH_OK: 'success', HEALTH_WARN: 'warningAltFilled', @@ -128,11 +130,15 @@ const PG_STATES = [ 'backfilling', 'backfill_wait', 'remapped', + 'unknown', // PROGRESS 'deep', 'scrubbing' ] as const; +// PROGRESS +const SCRUBBING_STATES = ['deep', 'scrubbing']; + const LABELS: Record = { scrubbing: 'Scrub', deep: 'Deep-Scrub' @@ -187,13 +193,13 @@ export const DATA_RESILIENCY: Record = { severity: DATA_RESILIENCY_STATE.progress }, [DATA_RESILIENCY_STATE.warn]: { - icon: 'warning', + icon: 'warningAltFilled', title: $localize`Restoring data redundancy`, description: $localize`Some data replicas are missing or not yet in their final location. Ceph is actively rebalancing data to return to a healthy state.`, severity: DATA_RESILIENCY_STATE.warn }, [DATA_RESILIENCY_STATE.warnDataLoss]: { - icon: 'warning', + icon: 'warningAltFilled', title: $localize`Status unavailable for some data`, description: $localize`Ceph cannot reliably determine the current state of some data. Availability may be affected.`, severity: DATA_RESILIENCY_STATE.warnDataLoss @@ -254,10 +260,7 @@ export function getResiliencyDisplay( } if (state === DATA_RESILIENCY_STATE.ok) { - const hasScrubbing = pgStates.some((s) => { - const n = s?.state_name ?? ''; - return n.includes('scrubbing') || n.includes('deep'); - }); + const hasScrubbing = pgStates.some((s) => isScrubbing(s?.state_name ?? '')); if (hasScrubbing) state = DATA_RESILIENCY_STATE.progress; } @@ -289,7 +292,7 @@ function isScrubbing(pgRow: string) { /** * If any PG state is active and not clean => Warn - * If any PG state is not active -> Error + * If any PG state is not active and not clean -> Error * * In case above is true, the states contributing to that as per * PG_STATES priotity List will be added. @@ -308,10 +311,11 @@ export function calcActiveCleanSeverityAndReasons( return { activeCleanPercent: 0, severity: DATA_RESILIENCY_STATE.ok, reasons: [] }; } - const reasonCounts = new Map(); + const errorWarnCounts = new Map(); + const scrubbingCounts = new Map(); + let reasonsMap: Map | Map = errorWarnCounts; let severity: ResiliencyState = DATA_RESILIENCY_STATE.ok; let activeCleanTotal = 0; - let hasProgress = false; let hasNotActiveNotClean = false; let hasActiveNotClean = false; @@ -325,8 +329,10 @@ export function calcActiveCleanSeverityAndReasons( if (isActive && !isClean) hasActiveNotClean = true; // If all okay then only scrubbing state is shown - if (!hasProgress && isScrubbing(stateName)) { - hasProgress = true; + for (const state of SCRUBBING_STATES) { + if (stateName.includes(state)) { + scrubbingCounts.set(state, (scrubbingCounts.get(state) ?? 0) + stateCount); + } } // active+clean*: no reasons required hence continuing @@ -335,10 +341,10 @@ export function calcActiveCleanSeverityAndReasons( continue; } - // Non active, non-clean or non-active+clean: reasons needed + // Any PG state that is not active+clean contributes to warning/error reasons for (const state of PG_STATES) { if (stateName.includes(state)) { - reasonCounts.set(state, (reasonCounts.get(state) ?? 0) + stateCount); + errorWarnCounts.set(state, (errorWarnCounts.get(state) ?? 0) + stateCount); break; } } @@ -346,12 +352,15 @@ export function calcActiveCleanSeverityAndReasons( if (hasNotActiveNotClean) severity = DATA_RESILIENCY_STATE.error; else if (hasActiveNotClean) severity = DATA_RESILIENCY_STATE.warn; - else if (hasProgress) severity = DATA_RESILIENCY_STATE.progress; + else if (scrubbingCounts.size > 0) { + severity = DATA_RESILIENCY_STATE.progress; + reasonsMap = scrubbingCounts; + } const reasons = - reasonCounts.size === 0 + reasonsMap?.size === 0 ? [] - : [...reasonCounts.entries()] + : [...reasonsMap.entries()] .sort((a, b) => b[1] - a[1]) .map(([state, count]) => ({ state: labelOf(state),