New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mgr/dashboard: Add text to empty life expectancy column #47876
Conversation
|
The CI steps which are failed are not apparently related to the changes included in this PR. |
| @@ -391,8 +391,17 @@ def safe_to_delete(self, svc_ids): | |||
|
|
|||
| @RESTController.Resource('GET') | |||
| def devices(self, svc_id): | |||
| devices: list = CephService.send_command( | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which is right type now? Is it a list or a dict as specified in line 403 (# (str) -> dict)?
@epuertat How are type hints handled in the Dashboard code nowadays?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having a look at it, it can return both a str or anything returned by json.loads:
ceph/src/pybind/mgr/dashboard/services/ceph_service.py
Lines 194 to 230 in 14189b7
| def send_command(srv_type, prefix, srv_spec='', **kwargs): | |
| # type: (str, str, Optional[str], Any) -> Any | |
| """ | |
| :type prefix: str | |
| :param srv_type: mon | | |
| :param kwargs: will be added to argdict | |
| :param srv_spec: typically empty. or something like "<fs_id>:0" | |
| :raises PermissionError: See rados.make_ex | |
| :raises ObjectNotFound: See rados.make_ex | |
| :raises IOError: See rados.make_ex | |
| :raises NoSpace: See rados.make_ex | |
| :raises ObjectExists: See rados.make_ex | |
| :raises ObjectBusy: See rados.make_ex | |
| :raises NoData: See rados.make_ex | |
| :raises InterruptedOrTimeoutError: See rados.make_ex | |
| :raises TimedOut: See rados.make_ex | |
| :raises ValueError: return code != 0 | |
| """ | |
| argdict = { | |
| "prefix": prefix, | |
| "format": "json", | |
| } | |
| argdict.update({k: v for k, v in kwargs.items() if v is not None}) | |
| result = CommandResult("") | |
| mgr.send_command(result, srv_type, srv_spec, json.dumps(argdict), "") | |
| r, outb, outs = result.wait() | |
| if r != 0: | |
| logger.error("send_command '%s' failed. (r=%s, outs=\"%s\", kwargs=%s)", prefix, r, | |
| outs, kwargs) | |
| raise SendCommandError(outs, prefix, argdict, r) | |
| try: | |
| return json.loads(outb or outs) | |
| except Exception: # pylint: disable=broad-except | |
| return outb |
| life_expectancy_enabled = any( | ||
| item.startswith('diskprediction_') for item in modules['enabled_modules']) | ||
| for device in devices: | ||
| device['life_expectancy_enabled'] = life_expectancy_enabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should think of a nicer way to deal with cross-module deps. @pereman2 as you're familiar with the ceph-mgr code, isn't there any way to detect whether another module is enabled/running? Or even better, declare that a module depends on others (new global var MODULE_DEPENDS or something like that?) and automatically enable/load them. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible ernesto, let me take a look.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pereman2 Any news here how to get a list of enabled mgr modules without running a send_command?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@torchiaf I think mgr.get('mgr_map') and mgr.get('mgr_map')['modules'] or mgr.get('mgr_map')['available_modules'] is the way to go. Have a look at https://github.com/ceph/ceph/blob/main/src/pybind/mgr/dashboard/controllers/mgr_modules.py#L47 how to get the required information. @pereman2 I'm right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is, MGRMap has all these info and you can get it with mgr.get('mgr_map'). I'll paste a snippet from controllers/mgr_modules.py where this is done.
result = []
mgr_map = mgr.get('mgr_map')
always_on_modules = mgr_map['always_on_modules'].get(mgr.release_name, [])
for module_config in mgr_map['available_modules']:
module_name = module_config['name']
if module_name not in self.ignore_modules:
always_on = module_name in always_on_modules
enabled = module_name in mgr_map['modules'] or always_on
result.append({
'name': module_name,
'enabled': enabled,
'always_on': always_on,
'options': self._convert_module_options(
module_config['module_options'])
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks guys, I will adapt my fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| <span *ngIf="!value.life_expectancy_enabled" | ||
| i18n>N/A</span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than dealing with null to N/A converstions case by case, what about implementing this in the datatable behaviour itself? I remember that @avanthakkar did this in other places, so I'd rather avoid doing this ad-hoc and implement it as a default behaviour of the column/cell template. What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@epuertat do you mean to put a new property, e.g. notAvailable: () => boolean, in TableColumn implementation ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@torchiaf: the component in which the Dashboard datatable is based on, ngx-datatable, supports a pipe property for each column. We already have a notAvailable pipe that converts an empty string to n/a:
ceph/src/pybind/mgr/dashboard/frontend/src/app/shared/pipes/not-available.pipe.ts
Lines 5 to 15 in f4df409
| @Pipe({ | |
| name: 'notAvailable' | |
| }) | |
| export class NotAvailablePipe implements PipeTransform { | |
| transform(value: any, text?: string): any { | |
| if (value === '') { | |
| return _.defaultTo(text, $localize`n/a`); | |
| } | |
| return value; | |
| } | |
| } |
Instead of implementing this same behaviour case by case, IMHO we should probably:
- Add that pipe by default to the cd-datatable
pipeproperty, - And extend that pipe to also check for
undefinedornulland display then/aon those cases.
Otherwise, we'll end up having to patch every single place where an empty/null/undefined string may appear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@epuertat I agree with you to put a default value when the value of a cell is null or undefined.
In our case however, I think It is different from the general case.
The value of lifeExpectancy column depends on many values (min, max, life_expectancy_enabled), it is not a simple translation null -> N/A.
ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/device-list/device-list.component.html
Lines 14 to 21 in 23f85cc
| <ng-template #lifeExpectancy | |
| let-value="value"> | |
| <span *ngIf="!value.life_expectancy_enabled" | |
| i18n>N/A</span> | |
| <span *ngIf="value.min && !value.max">> {{value.min | i18nPlural: translationMapping}}</span> | |
| <span *ngIf="value.max && !value.min">< {{value.max | i18nPlural: translationMapping}}</span> | |
| <span *ngIf="value.max && value.min">{{value.min}} to {{value.max | i18nPlural: translationMapping}}</span> | |
| </ng-template> |
My fix is supposed to works this way :
- when
minandmaxare empty, show empty value, because it means there are no enough data to calculate thelifeExpectancyvalue - when
life_expectancy_enabledis false, showN/A, because it means that the life expectancy module is disabled.
Probably, I should rename life_expectancy_enabled -> life_expectancy_module_enabled.
What do you think about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMO the column we're talk about is too specific to use generic pipes. In that case the implementation of a template within the component is right.
What can be done to limit the number of variations (N/A vs n/a) which are sadly spread across the whole code is using this:
<span *ngIf="!value.life_expectancy_enabled" i18n>{{ "" | notAvailable }}</span>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@votdev suggestion is good enough for this!
7dbec7a
to
d3f40f0
Compare
d3f40f0
to
fdb78b2
Compare
|
jenkins retest this please |
src/pybind/mgr/dashboard/frontend/src/app/ceph/shared/device-list/device-list.component.html
Outdated
Show resolved
Hide resolved
|
@torchiaf make check is failing due to linting issues, could you fix that please? [lint:tslint ] TSLint's support is discontinued and we're deprecating its support in Angular CLI. Try running 'npm run fix' to fix some linting errors. Some errors might need a manual fix. And also, try to keep commits squashed to have the history easier to read. |
- Add life_expectancy_enabled field to /api/osd/{svc_id}/devices
- Add new value 'n/a' for 'Life Expectancy' column
Fixes: https://tracker.ceph.com/issues/43116
Signed-off-by: Francesco Torchia <francesco.torchia@suse.com>
2e55bf3
to
811bba7
Compare
Hi @Pegonzal , sure, i just pushed the fix, thanks. |
|
jenkins test dashboard |

Fixes: https://tracker.ceph.com/issues/43116
Signed-off-by: Francesco Torchia francesco.torchia@suse.com
Contribution Guidelines
To sign and title your commits, please refer to Submitting Patches to Ceph.
If you are submitting a fix for a stable branch (e.g. "pacific"), please refer to Submitting Patches to Ceph - Backports for the proper workflow.
Checklist
Show available Jenkins commands
jenkins retest this pleasejenkins test classic perfjenkins test crimson perfjenkins test signedjenkins test make checkjenkins test make check arm64jenkins test submodulesjenkins test dashboardjenkins test dashboard cephadmjenkins test apijenkins test docsjenkins render docsjenkins test ceph-volume alljenkins test ceph-volume toxjenkins test windows