From: Nizamudeen A Date: Wed, 5 Mar 2025 16:46:03 +0000 (+0530) Subject: mgr/dashboard: fix access control permissions for roles X-Git-Tag: v20.3.0~313^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=f4bc03e4040ca32591d9b46b79309b162c3942db;p=ceph.git 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 --- 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 fa194024db9e..372e6baf3de5 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 fda0b407587a..6f5c535fd8d4 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 72314baac47f..c122d3bc0142 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 c3b740ec7c68..fa798ea067ac 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 c213ae26a599..fa1af615b27b 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 e0d508172feb..bdabdd0b6439 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 a544bbcdb436..13b0d86b7633 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 @@