From af7bc9ffa03d28acf577425e06b4a32651ae3e6c Mon Sep 17 00:00:00 2001 From: Pere Diaz Bou Date: Mon, 4 Jul 2022 16:57:43 +0200 Subject: [PATCH] mgr/dashboard: add rbd list sorting support Support sorting with name, pool name and namespace Signed-off-by: Pere Diaz Bou (cherry picked from commit 3c308804d5a7a5e96842e3234edbf6ad42509e93) Conflicts: src/pybind/mgr/dashboard/services/rbd.py remove _rbd_image_stat_parent function because it isn't used in pacific. --- qa/tasks/mgr/dashboard/test_rbd.py | 2 +- src/pybind/mgr/dashboard/controllers/rbd.py | 8 ++++---- .../ceph/block/rbd-list/rbd-list.component.ts | 5 +++-- .../src/app/shared/api/rbd.service.spec.ts | 2 +- .../shared/datatable/table/table.component.html | 1 + .../shared/datatable/table/table.component.ts | 7 +++++++ .../models/cd-table-fetch-data-context.ts | 9 +++++++-- src/pybind/mgr/dashboard/services/rbd.py | 17 +++++++++++++++-- 8 files changed, 39 insertions(+), 12 deletions(-) diff --git a/qa/tasks/mgr/dashboard/test_rbd.py b/qa/tasks/mgr/dashboard/test_rbd.py index 4e0367fd5be7..0bb4b49817e4 100644 --- a/qa/tasks/mgr/dashboard/test_rbd.py +++ b/qa/tasks/mgr/dashboard/test_rbd.py @@ -13,7 +13,7 @@ class RbdTest(DashboardTestCase): @DashboardTestCase.RunAs('test', 'test', [{'rbd-image': ['create', 'update', 'delete']}]) def test_read_access_permissions(self): - self._get('/api/block/image') + self._get('/api/block/image?offset=0&limit=5&search=&sort=%3Cname') self.assertStatus(403) self.get_image('pool', None, 'image') self.assertStatus(403) diff --git a/src/pybind/mgr/dashboard/controllers/rbd.py b/src/pybind/mgr/dashboard/controllers/rbd.py index d26fcfa7292b..943a09367205 100644 --- a/src/pybind/mgr/dashboard/controllers/rbd.py +++ b/src/pybind/mgr/dashboard/controllers/rbd.py @@ -80,14 +80,14 @@ class Rbd(RESTController): ALLOW_DISABLE_FEATURES = {"exclusive-lock", "object-map", "fast-diff", "deep-flatten", "journaling"} - def _rbd_list(self, pool_name=None, offset=0, limit=5, search=''): + def _rbd_list(self, pool_name=None, offset=0, limit=5, search='', sort=''): if pool_name: pools = [pool_name] else: pools = [p['pool_name'] for p in CephService.get_pool_list('rbd')] images, num_total_images = RbdService.rbd_pool_list( - pools, offset=offset, limit=limit, search=search) + pools, offset=offset, limit=limit, search=search, sort=sort) cherrypy.response.headers['X-Total-Count'] = num_total_images pool_result = {} for i, image in enumerate(images): @@ -111,8 +111,8 @@ class Rbd(RESTController): responses={200: RBD_SCHEMA}) @RESTController.MethodMap(version=APIVersion(2, 0)) # type: ignore def list(self, pool_name=None, offset: int = 0, limit: int = 5, - search: str = ''): - return self._rbd_list(pool_name, offset=offset, limit=limit, search=search) + search: str = '', sort: str = ''): + return self._rbd_list(pool_name, offset=offset, limit=limit, search=search, sort=sort) @handle_rbd_error() @handle_rados_error('pool') diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts index 71d712184869..983f39ed9be5 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-list/rbd-list.component.ts @@ -243,13 +243,11 @@ export class RbdListComponent extends ListWithDetails implements OnInit { { name: $localize`Pool`, prop: 'pool_name', - sortable: false, flexGrow: 2 }, { name: $localize`Namespace`, prop: 'namespace', - sortable: false, flexGrow: 2 }, { @@ -375,6 +373,9 @@ export class RbdListComponent extends ListWithDetails implements OnInit { if (context !== null) { this.tableContext = context; } + if (this.tableContext == null) { + this.tableContext = new CdTableFetchDataContext(() => undefined); + } return this.rbdService.list(this.tableContext?.toParams()); } diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rbd.service.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rbd.service.spec.ts index dc51614ffedd..f5ab8615ac65 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rbd.service.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/api/rbd.service.spec.ts @@ -59,7 +59,7 @@ describe('RbdService', () => { /* tslint:disable:no-empty */ const context = new CdTableFetchDataContext(() => {}); service.list(context.toParams()).subscribe(); - const req = httpTesting.expectOne('api/block/image?offset=0&limit=10'); + const req = httpTesting.expectOne('api/block/image?offset=0&limit=10?search=&sort='}${sort.prop}`; + } this.fetchData.emit(context); this.updating = true; } @@ -791,6 +795,9 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O changeSorting({ sorts }: any) { this.userConfig.sorts = sorts; + if (this.serverSide) { + this.reloadData(); + } } onClearSearch() { diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-fetch-data-context.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-fetch-data-context.ts index 56efadeb2bae..7f50bb7f1ec9 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-fetch-data-context.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/models/cd-table-fetch-data-context.ts @@ -16,6 +16,7 @@ export class CdTableFetchDataContext { error: Function; pageInfo: PageInfo = new PageInfo(); search = ''; + sort = '>name'; constructor(error: () => void) { this.error = error; @@ -25,14 +26,18 @@ export class CdTableFetchDataContext { if (this.pageInfo.limit === null) { this.pageInfo.limit = 0; } - if (this.search === null) { + if (!this.search) { this.search = ''; } + if (!this.sort) { + this.sort = '>name'; + } return new HttpParams({ fromObject: { offset: String(this.pageInfo.offset * this.pageInfo.limit), limit: String(this.pageInfo.limit), - search: this.search + search: this.search, + sort: this.sort } }); } diff --git a/src/pybind/mgr/dashboard/services/rbd.py b/src/pybind/mgr/dashboard/services/rbd.py index a0ee3ef70e75..95444cea6826 100644 --- a/src/pybind/mgr/dashboard/services/rbd.py +++ b/src/pybind/mgr/dashboard/services/rbd.py @@ -11,6 +11,7 @@ import rbd from .. import mgr from ..exceptions import DashboardException +from ..plugins.ttl_cache import ttl_cache from .ceph_service import CephService try: @@ -391,6 +392,7 @@ class RbdService(object): return stat @classmethod + @ttl_cache(10) def _rbd_image_refs(cls, ioctx): rbd_inst = rbd.RBD() return rbd_inst.list2(ioctx) @@ -437,7 +439,7 @@ class RbdService(object): return joint_refs @classmethod - def rbd_pool_list(cls, pool_names: List[str], namespace=None, offset=0, limit=0, search=''): + def rbd_pool_list(cls, pool_names: List[str], namespace=None, offset=0, limit=0, search='', sort=''): offset = int(offset) limit = int(limit) # let's use -1 to denotate we want ALL images for now. Iscsi currently gathers @@ -451,12 +453,23 @@ class RbdService(object): for ref in refs: if search in ref['name']: image_refs.append(ref) + elif search in ref['pool']: + image_refs.append(ref) + elif search in ref['namespace']: + image_refs.append(ref) result = [] end = offset + limit + descending = sort[0] == '<' + sort_by = sort[1:] + if sort_by == 'pool_name': + sort_by = 'pool' + if sort_by not in ['name', 'pool', 'namespace']: + sort_by = 'name' if limit == -1: end = len(image_refs) - for image_ref in sorted(image_refs, key=lambda v: v['name'])[offset:end]: + for image_ref in sorted(image_refs, key=lambda v: v[sort_by], + reverse=descending)[offset:end]: with mgr.rados.open_ioctx(image_ref['pool']) as ioctx: ioctx.set_namespace(image_ref['namespace']) try: -- 2.47.3