From e3b68ccb526c676c756d5b96344e3145f7801148 Mon Sep 17 00:00:00 2001 From: Aashish Sharma Date: Thu, 31 Aug 2023 16:16:32 +0530 Subject: [PATCH] mgr/dashboard: Object gateway inventory card incorrect Buckets and user count Inventory(Buckets and users) data is wrong when you have buckets across multiple daemons. Fixes: https://tracker.ceph.com/issues/62565 Signed-off-by: Aashish Sharma (cherry picked from commit f12dc8f9680b3b6f73fba897822c192bcd402b43) --- src/pybind/mgr/dashboard/controllers/rgw.py | 21 +++++ .../rgw-overview-dashboard.component.spec.ts | 82 ++----------------- .../rgw-overview-dashboard.component.ts | 16 ++-- .../src/app/shared/api/rgw-bucket.service.ts | 6 ++ 4 files changed, 39 insertions(+), 86 deletions(-) diff --git a/src/pybind/mgr/dashboard/controllers/rgw.py b/src/pybind/mgr/dashboard/controllers/rgw.py index 766c8eadc51e5..f7fdfef3f5829 100644 --- a/src/pybind/mgr/dashboard/controllers/rgw.py +++ b/src/pybind/mgr/dashboard/controllers/rgw.py @@ -439,6 +439,27 @@ class RgwBucket(RgwRESTController): return CephService.get_encryption_config(daemon_name) +@UIRouter('/rgw/bucket', Scope.RGW) +class RgwBucketUi(RgwBucket): + @Endpoint('GET') + @ReadPermission + # pylint: disable=W0613 + def buckets_and_users_count(self, daemon_name=None): + buckets_count = 0 + users_count = 0 + daemon_object = RgwDaemon() + daemons = json.loads(daemon_object.list()) + for daemon in daemons: + buckets = json.loads(RgwBucket.list(self, daemon_name=daemon['id'])) + users = json.loads(RgwUser.list(self, daemon_name=daemon['id'])) + users_count += len(users) + buckets_count += len(buckets) + return { + 'buckets_count': buckets_count, + 'users_count': users_count + } + + @APIRouter('/rgw/user', Scope.RGW) @APIDoc("RGW User Management API", "RgwUser") class RgwUser(RgwRESTController): diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.spec.ts index 1f759abd93442..aae0d74924a1f 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.spec.ts @@ -10,7 +10,6 @@ import { RgwRealmService } from '~/app/shared/api/rgw-realm.service'; import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service'; import { RgwZoneService } from '~/app/shared/api/rgw-zone.service'; import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service'; -import { RgwUserService } from '~/app/shared/api/rgw-user.service'; import { HealthService } from '~/app/shared/api/health.service'; import { CardComponent } from '~/app/shared/components/card/card.component'; import { CardRowComponent } from '~/app/shared/components/card-row/card-row.component'; @@ -45,73 +44,10 @@ describe('RgwOverviewDashboardComponent', () => { zones: ['zone4', 'zone5', 'zone6', 'zone7'] }; - const bucketList = [ - { - bucket: 'bucket', - owner: 'testid', - usage: { - 'rgw.main': { - size_actual: 4, - num_objects: 2 - }, - 'rgw.none': { - size_actual: 6, - num_objects: 6 - } - }, - bucket_quota: { - max_size: 20, - max_objects: 10, - enabled: true - } - }, - { - bucket: 'bucket2', - owner: 'testid', - usage: { - 'rgw.main': { - size_actual: 4, - num_objects: 2 - }, - 'rgw.none': { - size_actual: 6, - num_objects: 6 - } - }, - bucket_quota: { - max_size: 20, - max_objects: 10, - enabled: true - } - } - ]; - - const userList = [ - { - user_id: 'testid', - stats: { - size_actual: 6, - num_objects: 6 - }, - user_quota: { - max_size: 20, - max_objects: 10, - enabled: true - } - }, - { - user_id: 'testid2', - stats: { - size_actual: 6, - num_objects: 6 - }, - user_quota: { - max_size: 20, - max_objects: 10, - enabled: true - } - } - ]; + const bucketAndUserList = { + buckets_count: 2, + users_count: 2 + }; const healthData = { total_objects: '290', @@ -123,7 +59,6 @@ describe('RgwOverviewDashboardComponent', () => { let listZonegroupsSpy: jest.SpyInstance; let listRealmsSpy: jest.SpyInstance; let listBucketsSpy: jest.SpyInstance; - let listUsersSpy: jest.SpyInstance; let healthDataSpy: jest.SpyInstance; beforeEach(async () => { @@ -150,9 +85,8 @@ describe('RgwOverviewDashboardComponent', () => { .mockReturnValue(of(zonegroupList)); listZonesSpy = jest.spyOn(TestBed.inject(RgwZoneService), 'list').mockReturnValue(of(zoneList)); listBucketsSpy = jest - .spyOn(TestBed.inject(RgwBucketService), 'list') - .mockReturnValue(of(bucketList)); - listUsersSpy = jest.spyOn(TestBed.inject(RgwUserService), 'list').mockReturnValue(of(userList)); + .spyOn(TestBed.inject(RgwBucketService), 'getTotalBucketsAndUsersLength') + .mockReturnValue(of(bucketAndUserList)); healthDataSpy = jest .spyOn(TestBed.inject(HealthService), 'getClusterCapacity') .mockReturnValue(of(healthData)); @@ -194,10 +128,6 @@ describe('RgwOverviewDashboardComponent', () => { it('should get corresponding data into Buckets', () => { expect(listBucketsSpy).toHaveBeenCalled(); expect(component.rgwBucketCount).toEqual(2); - }); - - it('should get corresponding data into Users', () => { - expect(listUsersSpy).toHaveBeenCalled(); expect(component.UserCount).toEqual(2); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts index b8c4774bec17f..f761d7e7b8f46 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/rgw/rgw-overview-dashboard/rgw-overview-dashboard.component.ts @@ -11,7 +11,6 @@ import { RgwRealmService } from '~/app/shared/api/rgw-realm.service'; import { RgwZoneService } from '~/app/shared/api/rgw-zone.service'; import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service'; import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service'; -import { RgwUserService } from '~/app/shared/api/rgw-user.service'; import { PrometheusService } from '~/app/shared/api/prometheus.service'; import { RgwPromqls as queries } from '~/app/shared/enum/dashboard-promqls.enum'; @@ -46,7 +45,6 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy { multisiteInfo: object[] = []; ZonegroupSub: Subscription; ZoneSUb: Subscription; - UserSub: Subscription; HealthSub: Subscription; BucketSub: Subscription; queriesResults: any = { @@ -78,7 +76,6 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy { private rgwZonegroupService: RgwZonegroupService, private rgwZoneService: RgwZoneService, private rgwBucketService: RgwBucketService, - private rgwUserService: RgwUserService, private prometheusService: PrometheusService, private rgwMultisiteService: RgwMultisiteService ) { @@ -90,12 +87,6 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy { this.daemonSub = this.rgwDaemonService.list().subscribe((data: any) => { this.rgwDaemonCount = data.length; }); - this.BucketSub = this.rgwBucketService.list().subscribe((data: any) => { - this.rgwBucketCount = data.length; - }); - this.UserSub = this.rgwUserService.list().subscribe((data: any) => { - this.UserCount = data.length; - }); this.HealthSub = this.healthService.getClusterCapacity().subscribe((data: any) => { this.objectCount = data['total_objects']; this.totalPoolUsedBytes = data['total_pool_bytes_used']; @@ -103,6 +94,12 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy { }); this.getSyncStatus(); }); + this.BucketSub = this.rgwBucketService + .getTotalBucketsAndUsersLength() + .subscribe((data: any) => { + this.rgwBucketCount = data['buckets_count']; + this.UserCount = data['users_count']; + }); this.realmSub = this.rgwRealmService.list().subscribe((data: any) => { this.rgwRealmCount = data['realms'].length; }); @@ -143,7 +140,6 @@ export class RgwOverviewDashboardComponent implements OnInit, OnDestroy { this.ZonegroupSub.unsubscribe(); this.ZoneSUb.unsubscribe(); this.BucketSub.unsubscribe(); - this.UserSub.unsubscribe(); this.HealthSub.unsubscribe(); if (this.timerGetPrometheusDataSub) { this.timerGetPrometheusDataSub.unsubscribe(); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts index 315c8b7560f17..7207d0b5ca72c 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rgw-bucket.service.ts @@ -43,6 +43,12 @@ export class RgwBucketService extends ApiClient { }); } + getTotalBucketsAndUsersLength() { + return this.rgwDaemonService.request((params: HttpParams) => { + return this.http.get(`ui-${this.url}/buckets_and_users_count`, { params: params }); + }); + } + create( bucket: string, uid: string, -- 2.39.5