From f4bc03e4040ca32591d9b46b79309b162c3942db Mon Sep 17 00:00:00 2001 From: Nizamudeen A Date: Wed, 5 Mar 2025 22:16:03 +0530 Subject: [PATCH] mgr/dashboard: fix access control permissions for roles Since prometheus is being used in the dashboard page we need to make sure every role has prometheus read only access so that the dashboard page can load the utilization metrics. I also saw permission issue with the osd settings endpoint when its trying to get the nearfull/full ratio. so instead of failing the entire page i am proceeding with a chart that doesn't have those details when the user doesn't have permission to access the config opt. Multisite page was not accessible in the case of rgw-manager or read-only user because its trying to show the status of rgw module. This si also now gracefully handled to show the alert only when the user has sufficient permission. Fixes: https://tracker.ceph.com/issues/70331 Signed-off-by: Nizamudeen A --- .../dashboard-pie/dashboard-pie.component.ts | 10 +++--- .../dashboard/dashboard-v3.component.html | 2 +- .../dashboard/dashboard-v3.component.ts | 19 +++++++----- .../rgw-multisite-details.component.html | 13 ++++---- .../rgw-multisite-details.component.ts | 31 ++++++++----------- .../administration.component.html | 3 +- .../navigation/navigation.component.html | 4 ++- .../mgr/dashboard/services/access_control.py | 10 ++++-- 8 files changed, 50 insertions(+), 42 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts index fa194024db9..372e6baf3de 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard-pie/dashboard-pie.component.ts @@ -15,9 +15,9 @@ export class DashboardPieComponent implements OnChanges, OnInit { @Input() data: any; @Input() - highThreshold: number; + highThreshold = 0; @Input() - lowThreshold: number; + lowThreshold = 0; color: string; @@ -162,15 +162,15 @@ export class DashboardPieComponent implements OnChanges, OnInit { const percentAvailable = this.calcPercentage(max - current, max); const percentUsed = this.calcPercentage(current, max); - if (fullRatioPercent >= 0 && percentUsed >= fullRatioPercent) { + if (fullRatioPercent > 0 && percentUsed >= fullRatioPercent) { this.color = 'chart-color-red'; - } else if (nearFullRatioPercent >= 0 && percentUsed >= nearFullRatioPercent) { + } else if (nearFullRatioPercent > 0 && percentUsed >= nearFullRatioPercent) { this.color = 'chart-color-yellow'; } else { this.color = 'chart-color-blue'; } - if (fullRatioPercent >= 0 && nearFullRatioPercent >= 0) { + if (fullRatioPercent > 0 && nearFullRatioPercent > 0) { chart.dataset[0].data = [ Math.round(nearFullRatioPercent), Math.round(Math.abs(nearFullRatioPercent - fullRatioPercent)), diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html index fda0b407587..6f5c535fd8d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.html @@ -227,7 +227,7 @@ [fullHeight]="true" aria-label="Capacity card"> + *ngIf="capacity"> diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts index 72314baac47..c122d3bc014 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/dashboard-v3/dashboard/dashboard-v3.component.ts @@ -26,6 +26,7 @@ import { MgrModuleService } from '~/app/shared/api/mgr-module.service'; import { AlertClass } from '~/app/shared/enum/health-icon.enum'; import { HardwareService } from '~/app/shared/api/hardware.service'; import { SettingsService } from '~/app/shared/api/settings.service'; +import { OsdSettings } from '~/app/shared/models/osd-settings'; @Component({ selector: 'cd-dashboard-v3', @@ -35,7 +36,7 @@ import { SettingsService } from '~/app/shared/api/settings.service'; export class DashboardV3Component extends PrometheusListHelper implements OnInit, OnDestroy { detailsCardData: DashboardDetails = {}; osdSettingsService: any; - osdSettings: any; + osdSettings = new OsdSettings(); interval = new Subscription(); permissions: Permissions; enabledFeature$: FeatureTogglesMap$; @@ -117,7 +118,8 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit } this.interval = this.refreshIntervalService.intervalData$.subscribe(() => { this.getHealth(); - this.getCapacityCardData(); + this.getCapacity(); + if (this.permissions.configOpt.read) this.getOsdSettings(); if (this.hardwareEnabled) this.hardwareSubject.next([]); }); this.getPrometheusData(this.prometheusService.lastHourDateObject); @@ -165,16 +167,19 @@ export class DashboardV3Component extends PrometheusListHelper implements OnInit ); } - getCapacityCardData() { + private getCapacity() { + this.capacityService = this.healthService.getClusterCapacity().subscribe((data: any) => { + this.capacity = data; + }); + } + + private getOsdSettings() { this.osdSettingsService = this.osdService .getOsdSettings() .pipe(take(1)) - .subscribe((data: any) => { + .subscribe((data: OsdSettings) => { this.osdSettings = data; }); - this.capacityService = this.healthService.getClusterCapacity().subscribe((data: any) => { - this.capacity = data; - }); } public getPrometheusData(selectedTime: any) { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html index c3b740ec7c6..fa798ea067a 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.html @@ -1,6 +1,7 @@
- + Services diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts index c213ae26a59..fa1af615b27 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-multisite-details/rgw-multisite-details.component.ts @@ -21,7 +21,7 @@ import { Icons } from '~/app/shared/enum/icons.enum'; import { NotificationType } from '~/app/shared/enum/notification-type.enum'; import { CdTableAction } from '~/app/shared/models/cd-table-action'; import { CdTableSelection } from '~/app/shared/models/cd-table-selection'; -import { Permission } from '~/app/shared/models/permissions'; +import { Permissions } from '~/app/shared/models/permissions'; import { AuthStorageService } from '~/app/shared/services/auth-storage.service'; import { ModalService } from '~/app/shared/services/modal.service'; import { NotificationService } from '~/app/shared/services/notification.service'; @@ -68,7 +68,7 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit { blockUI: NgBlockUI; icons = Icons; - permission: Permission; + permissions: Permissions; selection = new CdTableSelection(); createTableActions: CdTableAction[]; migrateTableAction: CdTableAction[]; @@ -144,7 +144,7 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit { private rgwMultisiteService: RgwMultisiteService, private changeDetectionRef: ChangeDetectorRef ) { - this.permission = this.authStorageService.getPermissions().rgw; + this.permissions = this.authStorageService.getPermissions(); } openModal(entity: any | string, edit = false) { @@ -305,22 +305,17 @@ export class RgwMultisiteDetailsComponent implements OnDestroy, OnInit { }, (_error) => {} ); - this.mgrModuleService.list().subscribe((moduleData: any) => { - this.rgwModuleData = moduleData.filter((module: object) => module['name'] === 'rgw'); - if (this.rgwModuleData.length > 0) { - this.rgwModuleStatus = this.rgwModuleData[0].enabled; - } - }); + + // Only get the module status if you can read from configOpt + if (this.permissions.configOpt.read) { + this.mgrModuleService.list().subscribe((moduleData: any) => { + this.rgwModuleData = moduleData.filter((module: object) => module['name'] === 'rgw'); + if (this.rgwModuleData.length > 0) { + this.rgwModuleStatus = this.rgwModuleData[0].enabled; + } + }); + } } - /* setConfigValues() { - this.rgwDaemonService - .setMultisiteConfig( - this.defaultsInfo['defaultRealmName'], - this.defaultsInfo['defaultZonegroupName'], - this.defaultsInfo['defaultZoneName'] - ) - .subscribe(() => {}); - }*/ ngOnDestroy() { this.sub.unsubscribe(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/administration/administration.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/administration/administration.component.html index e0d508172fe..bdabdd0b643 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/administration/administration.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/administration/administration.component.html @@ -1,7 +1,6 @@ -
  • +
  • diff --git a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html index a544bbcdb43..13b0d86b763 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/core/navigation/navigation/navigation.component.html @@ -39,7 +39,8 @@
    -
    +
    @@ -93,6 +94,7 @@