Currently always-on modules are not marked as enabled in the WebUI and can be disabled. This PR will fix that.
Note, this PR will NOT implement code that will prevent a developer from trying to disable an always-on module through the REST API. The Mgr Python extension will throw an adequate exception.
This PR will also do:
* Remove old code fragments from a previous Mgr Module management UI that is obsolete now.
* Cleanup code in BaseMgrModule code.
Fixes: https://tracker.ceph.com/issues/41648
Signed-off-by: Volker Theile <vtheile@suse.com>
}
static PyObject *
-ceph_get_context(BaseMgrModule *self, PyObject *args)
+ceph_get_release_name(BaseMgrModule *self, PyObject *args)
+{
+ return PyString_FromString(ceph_release_to_str());
+}
+
+static PyObject *
+ceph_get_context(BaseMgrModule *self)
{
return self->py_modules->get_context();
}
{"_ceph_cluster_log", (PyCFunction)ceph_cluster_log, METH_VARARGS,
"Emit a cluster log message"},
- {"_ceph_get_version", (PyCFunction)ceph_get_version, METH_VARARGS,
+ {"_ceph_get_version", (PyCFunction)ceph_get_version, METH_NOARGS,
"Get the ceph version of this process"},
+ {"_ceph_get_release_name", (PyCFunction)ceph_get_release_name, METH_NOARGS,
+ "Get the ceph release name of this process"},
+
{"_ceph_get_context", (PyCFunction)ceph_get_context, METH_NOARGS,
"Get a CephContext* in a python capsule"},
"""
result = []
mgr_map = mgr.get('mgr_map')
+ always_on_modules = mgr_map['always_on_modules'][mgr.release_name]
for module_config in mgr_map['available_modules']:
- if module_config['name'] not in self.ignore_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_config['name'],
- 'enabled': False,
+ 'name': module_name,
+ 'enabled': enabled,
+ 'always_on': always_on,
'options': self._convert_module_options(
module_config['module_options'])
})
- for name in mgr_map['modules']:
- if name not in self.ignore_modules:
- obj = find_object_in_list('name', name, result)
- obj['enabled'] = True
return result
def get(self, module_name):
spyOn(mgrModuleService, 'list').and.returnValues(observableThrowError('z'), observableOf([]));
component.selection.selected.push({
name: 'foo',
- enabled: false
+ enabled: false,
+ always_on: false
});
component.selection.update();
component.updateModuleState();
spyOn(mgrModuleService, 'list').and.returnValue(observableOf([]));
component.selection.selected.push({
name: 'bar',
- enabled: true
+ enabled: true,
+ always_on: false
});
component.selection.update();
component.updateModuleState();
expect(component.blockUI.stop).toHaveBeenCalled();
expect(component.table.refreshBtn).toHaveBeenCalled();
}));
+
+ it('should not disable module (1)', () => {
+ component.selection.selected = [
+ {
+ name: 'dashboard'
+ }
+ ];
+ component.selection.update();
+ expect(component.isTableActionDisabled('enabled')).toBeTruthy();
+ });
+
+ it('should not disable module (2)', () => {
+ component.selection.selected = [
+ {
+ name: 'bar',
+ always_on: true
+ }
+ ];
+ component.selection.update();
+ expect(component.isTableActionDisabled('enabled')).toBeTruthy();
+ });
});
});
permission: 'update',
click: () => this.updateModuleState(),
disable: () => this.isTableActionDisabled('disabled'),
+ disableDesc: () => this.getTableActionDisabledDesc(),
icon: Icons.stop
}
];
if (!this.selection.hasSelection) {
return true;
}
+ const selected = this.selection.first();
// Make sure the user can't modify the run state of the 'Dashboard' module.
// This check is only done in the UI because the REST API should still be
// able to do so.
- if (this.selection.first().name === 'dashboard') {
+ if (selected.name === 'dashboard') {
+ return true;
+ }
+ // Always-on modules can't be disabled.
+ if (selected.always_on) {
return true;
}
switch (state) {
case 'enabled':
- return this.selection.first().enabled;
+ return selected.enabled;
case 'disabled':
- return !this.selection.first().enabled;
+ return !selected.enabled;
+ }
+ }
+
+ getTableActionDisabledDesc(): string | undefined {
+ if (this.selection.hasSelection) {
+ const selected = this.selection.first();
+ if (selected.always_on) {
+ return this.i18n('This Manager module is always on.');
+ }
}
}
def version(self):
return self._version
+ @property
+ def release_name(self):
+ """
+ Get the release name of the Ceph version, e.g. 'nautilus' or 'octopus'.
+ :return: Returns the release name of the Ceph version in lower case.
+ :rtype: str
+ """
+ return self._ceph_get_release_name()
+
def get_context(self):
"""
:return: a Python capsule containing a C++ CephContext pointer