From: Pere Diaz Bou Date: Mon, 4 Jul 2022 14:57:43 +0000 (+0200) Subject: mgr/dashboard: add rbd list sorting support X-Git-Tag: v16.2.11~407^2~6 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=af7bc9ffa03d28acf577425e06b4a32651ae3e6c;p=ceph.git 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. --- diff --git a/qa/tasks/mgr/dashboard/test_rbd.py b/qa/tasks/mgr/dashboard/test_rbd.py index 4e0367fd5be..0bb4b49817e 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 d26fcfa7292..943a0936720 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 71d71218486..983f39ed9be 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 dc51614ffed..f5ab8615ac6 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 56efadeb2ba..7f50bb7f1ec 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 a0ee3ef70e7..95444cea682 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: