@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)
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):
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')
{
name: $localize`Pool`,
prop: 'pool_name',
- sortable: false,
flexGrow: 2
},
{
name: $localize`Namespace`,
prop: 'namespace',
- sortable: false,
flexGrow: 2
},
{
if (context !== null) {
this.tableContext = context;
}
+ if (this.tableContext == null) {
+ this.tableContext = new CdTableFetchDataContext(() => undefined);
+ }
return this.rbdService.list(this.tableContext?.toParams());
}
/* 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=<name');
expect(req.request.method).toBe('GET');
});
[footerHeight]="footer ? 'auto' : 0"
[count]="count"
[externalPaging]="serverSide"
+ [externalSorting]="serverSide"
[limit]="userConfig.limit > 0 ? userConfig.limit : undefined"
[offset]="userConfig.offset >= 0 ? userConfig.offset : 0"
(page)="changePage($event)"
context.pageInfo.offset = this.userConfig.offset;
context.pageInfo.limit = this.userConfig.limit;
context.search = this.userConfig.search;
+ if (this.userConfig.sorts?.length) {
+ const sort = this.userConfig.sorts[0];
+ context.sort = `${sort.dir == 'desc' ? '<' : '>'}${sort.prop}`;
+ }
this.fetchData.emit(context);
this.updating = true;
}
changeSorting({ sorts }: any) {
this.userConfig.sorts = sorts;
+ if (this.serverSide) {
+ this.reloadData();
+ }
}
onClearSearch() {
error: Function;
pageInfo: PageInfo = new PageInfo();
search = '';
+ sort = '>name';
constructor(error: () => void) {
this.error = error;
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
}
});
}
from .. import mgr
from ..exceptions import DashboardException
+from ..plugins.ttl_cache import ttl_cache
from .ceph_service import CephService
try:
return stat_parent
@classmethod
+ @ttl_cache(10)
def _rbd_image_refs(cls, ioctx):
rbd_inst = rbd.RBD()
return rbd_inst.list2(ioctx)
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
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: