Conversation
batrick
left a comment
There was a problem hiding this comment.
Also, maybe a separate PR for pybind/.../dashboard: misc automatic linter fixes?
| def make_registry_subtype(cls, name) -> 'CLICommandBase': | ||
| return type(name, (cls,), { | ||
| 'COMMANDS': {}, | ||
| }) |
There was a problem hiding this comment.
You could avoid this construction (and all of the associated cli.py files and CLICommand = class members):
MirroringCLICommand = CLICommandBase.make_registry_subtype("MirroringCLICommand")
by doing something like:
class CLICommand:
...
def __init__(self, mgrm_cls, prefix, "w", poll):
COMMANDS = mgrm_cls.set_default('COMMANDS', {})
...
@classmethod
def Write(cls,mgrm_cls,prefix,poll):
return cls(mgrm_cls, prefix, "w", poll)
@CLICommand.Write(locals(), 'fs snapshot mirror enable')
def snapshot_mirror_enable(self, fs_name: str):
Obviously, the key bit there is the slightly onerous passing of locals() to the CLICommand so that it can put the COMMANDS dict in the module class definition.
Anyway, I also think what you have done is clear so I'm good with this either way.
There was a problem hiding this comment.
Passing in locals() doesn't really seem cleaner than this.
My original draft (#66415) was able to hide all of this (except for the more special cases like dashboard and cephadm/orchestrator) by using a metaclass to inject a magic CLICommand (along with the other globals) into the class namespace prior to executing class body of the modules derived from MgrModule. @zmc wasn't fond of the level of magic. Tracking down and untangling the knot of magic that already existed between CLICommand and its users cost me a ton of time, so I ended up generating the explicit boilerplate here instead to avoid passing something confusing like that along.
The linter commit is because I needed it to make tox happy. I don't actually understand how those files merged like that unless making tox happy isn't actually a merge requirement.
| return all_results | ||
|
|
||
| @cli.SMBCommand('apply', perm='rw') | ||
| @SMBCLICommand('apply', perm='rw') |
There was a problem hiding this comment.
Maybe I don't fully understand something, but these lines seem like unnecessary churn to me? Is there a reason not to CLICommand = cli.SMBCLICommand above and leave these lines alone? It's the same object after all (AFAICT).
There was a problem hiding this comment.
This way it matches every other cli command decorator in pybind/mgr.
There was a problem hiding this comment.
OK, fair enough for now.
phlogistonjohn
left a comment
There was a problem hiding this comment.
most of these patches look generally OK to me. I do have a few q's about stuff that are more like 'preference or necessary change'? :-)
| def dump_cmd_list(cls) -> List[Dict[str, Union[str, bool]]]: | ||
| return [cmd.dump_cmd() for cmd in cls.COMMANDS.values()] | ||
|
|
||
| def Read(cls, prefix: str, poll: bool = False) -> 'CLICommandBase': |
There was a problem hiding this comment.
Is there a compatibility reason for the capital-R? It's not pep8 compliant. If it's necessary, can we add a comment noting the reason?
There was a problem hiding this comment.
No, just chose to match the capitalization of CLIReadCommand and CLIWriteCommand. tox is ok with it. I'm not really inclined to change it unless it really bothers you.
There was a problem hiding this comment.
OK, I will ignore it for now but I do have plans to enable more linters on the python code in ceph (a lot of stuff for mgr is old and exempt right now) eventually and if the linters start complaining in the future I may end up changing it, but if they don't complain I will continue to ignore it.
There was a problem hiding this comment.
Python is snake_case by default. All-caps/CamelCase is just reserved for GLOBALS and ClassNames. This should be easy to fix, you know s/\.Read.../....
|
|
||
|
|
||
| class DecoDemo: | ||
| class DecoDemo(object): |
There was a problem hiding this comment.
I'm so curious.... did not having object as a base actually have visible behavhior impacts on python 3?
There was a problem hiding this comment.
shrug matches other code now.
There was a problem hiding this comment.
Well, that's probably because that code is older and either supported python 2 or carried over that pattern from python 2 out of habit. I won't ask you to change it but I may change it back the next time I need to work on that module. :-)
|
I ran rados suite on the branch-of-the-day (wip-rocky10-branch-of-the-day-2025-12-01-1764638786) that includes that PR, the results are in https://tracker.ceph.com/issues/74070 and look good (accept a few segfaults that we already saw) |
|
This PR is under test in https://tracker.ceph.com/issues/74161. |
|
This pull request can no longer be automatically merged: a rebase is needed and changes have to be manually resolved |
9daaea2 to
8231b8e
Compare
8231b8e to
4aa9e24
Compare
epuertat
left a comment
There was a problem hiding this comment.
First of all, kudos for tackling such an unpleasant duty 😅 The COMMANDS part and all the many layers built on top of it (the decorators, global registry, etc.) definitely requires a refactoring/clean-up.
I'm not sure if I'm missing anything with the original issue, but if it had to do with the base class ClassVars shared across subclasses, Python provides a way to deal with that situation, the __init_subclass__ hook, explicitly designed to avoid having to deal with metaclasses:
class MgrModule(ceph_module.BaseMgrModule, MgrModuleLoggingMixin):
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.COMMANDS = []
...| def dump_cmd_list(cls) -> List[Dict[str, Union[str, bool]]]: | ||
| return [cmd.dump_cmd() for cmd in cls.COMMANDS.values()] | ||
|
|
||
| def Read(cls, prefix: str, poll: bool = False) -> 'CLICommandBase': |
There was a problem hiding this comment.
Python is snake_case by default. All-caps/CamelCase is just reserved for GLOBALS and ClassNames. This should be easy to fix, you know s/\.Read.../....
| return cls(prefix, "r", poll) | ||
|
|
||
| @classmethod | ||
| def Write(cls, prefix: str, poll: bool = False) -> 'CLICommandBase': |
There was a problem hiding this comment.
Same here:
| def Write(cls, prefix: str, poll: bool = False) -> 'CLICommandBase': | |
| def write(cls, prefix: str, poll: bool = False) -> 'CLICommandBase': |
There was a problem hiding this comment.
Write and Read are simply wrappers around the CLICommand constructor, so I figured caps would be better.
Given the length of time that this has been tested and up for review and the urgency of merging it for rocky10 support, I'm not inclined to change it at this point unless you feel really strongly.
| self.get_ceph_option(opt)) | ||
| self.log.debug(' native option %s = %s', opt, getattr(self, opt)) | ||
|
|
||
| @CLIReadCommand('alerts send') |
There was a problem hiding this comment.
If possible I'd suggest that we keep the original interface as much as possible (@CLI*Command) and no Read/Write methods, in order to reduce conflicts with backports.
There was a problem hiding this comment.
My original solution used some subtle metaclass trickery to avoid changing a bunch of code, but @zmc asked me to do it more explicitly. Given the difficulty of untangling the magic around the old mechanism (and mechanisms for subverting it in some modules), I agreed that this would probably be a lot more maintainable.
|
|
||
|
|
||
| class Alerts(MgrModule): | ||
| CLICommand = AlertsCLICommand |
There was a problem hiding this comment.
Maybe this alias was here to reduce interface changes and keep the @CLICommand decorator?
There was a problem hiding this comment.
MgrModule uses it for command registration. I'm reluctant to use CLICommand in the decorators in the body as I wanted it to be obvious which CLICommand subclass was actually being used. Doing it this way allows one to actually grep for uses of any particular CLICommand subclass and allows decorators in MgrModule bodies to match those not in MgrModule bodies.
|
@ljflores Can you arrange for this PR to be tested on its own (no need for rocky10, suite changes, or any of the other PRs)? It should work in isolation, and that would let us merge it ahead of other fixes. |
@athanatos ACK |
|
jenkins test all |
|
jenkins test make check |
|
jenkins test make check arm64 |
|
jenkins test dashboard |
|
jenkins test dashboard cephadm |
|
jenkins test api |
|
jenkins retest this please |
|
jenkins retest this please |
|
This PR is blocked by these bugs:
I have asked Casey and Ilya to triage them. |
|
The only blocker here is https://tracker.ceph.com/issues/74809. The two RBD issues aren't new, they are intermittent and typically go away on a retrigger. This is evidenced by the current make check (arm64) failure: |
|
This is an automated message by src/script/redmine-upkeep.py. I have resolved the following tracker ticket due to the merge of this PR: No backports are pending for the ticket. If this is incorrect, please update the tracker Update Log: https://github.com/ceph/ceph/actions/runs/21766408041 |
Update documentation to reflect the new per-module command registry pattern introduced in PR ceph#66467. The old global CLICommand decorators have been replaced with module-specific registries. Changes: - doc/mgr/modules.rst: Rewrite CLICommand section with setup guide, update all examples to use AntigravityCLICommand pattern - src/pybind/mgr/object_format.py: Add note explaining per-module registries and update all decorator examples - doc/dev/developer_guide/dash-devel.rst: Update dashboard plugin examples to use DBCLICommand All examples now correctly show: - Creating registry with CLICommandBase.make_registry_subtype() - Using module-specific decorator names (e.g., @StatusCLICommand.Read) - Setting CLICommand class attribute for framework registration Signed-off-by: Kefu Chai <k.chai@proxmox.com>
Update documentation to reflect the new per-module command registry pattern introduced in PR ceph#66467. The old global CLICommand decorators have been replaced with module-specific registries. Changes: - doc/mgr/modules.rst: Rewrite CLICommand section with setup guide, update all examples to use AntigravityCLICommand pattern - src/pybind/mgr/object_format.py: Add note explaining per-module registries and update all decorator examples - doc/dev/developer_guide/dash-devel.rst: Update dashboard plugin examples to use DBCLICommand All examples now correctly show: - Creating registry with CLICommandBase.make_registry_subtype() - Using module-specific decorator names (e.g., @StatusCLICommand.Read) - Setting CLICommand class attribute for framework registration Signed-off-by: Kefu Chai <k.chai@proxmox.com>
Update documentation to reflect the new per-module command registry pattern introduced in PR ceph#66467. The old global CLICommand decorators have been replaced with module-specific registries. Changes: - doc/mgr/modules.rst: Rewrite CLICommand section with setup guide, update all examples to use AntigravityCLICommand pattern - src/pybind/mgr/object_format.py: Add note explaining per-module registries and update all decorator examples - doc/dev/developer_guide/dash-devel.rst: Update dashboard plugin examples to use DBCLICommand All examples now correctly show: - Creating registry with CLICommandBase.make_registry_subtype() - Using module-specific decorator names (e.g., @StatusCLICommand.Read) - Setting CLICommand class attribute for framework registration Signed-off-by: Kefu Chai <k.chai@proxmox.com>
Update documentation to reflect the new per-module command registry pattern introduced in PR ceph#66467. The old global CLICommand decorators have been replaced with module-specific registries. Changes: - doc/mgr/modules.rst: Rewrite CLICommand section with setup guide, update all examples to use AntigravityCLICommand pattern - src/pybind/mgr/object_format.py: Add note explaining per-module registries and update all decorator examples - doc/dev/developer_guide/dash-devel.rst: Update dashboard plugin examples to use DBCLICommand All examples now correctly show: - Creating registry with CLICommandBase.make_registry_subtype() - Using module-specific decorator names (e.g., @StatusCLICommand.Read) - Setting CLICommand class attribute for framework registration Signed-off-by: Kefu Chai <k.chai@proxmox.com>
Update documentation to reflect the new per-module command registry pattern introduced in PR ceph#66467. The old global CLICommand decorators have been replaced with module-specific registries. Changes: - doc/mgr/modules.rst: Rewrite CLICommand section with setup guide, update all examples to use AntigravityCLICommand pattern - src/pybind/mgr/object_format.py: Add note explaining per-module registries and update all decorator examples - doc/dev/developer_guide/dash-devel.rst: Update dashboard plugin examples to use DBCLICommand All examples now correctly show: - Creating registry with CLICommandBase.make_registry_subtype() - Using module-specific decorator names (e.g., @StatusCLICommand.Read) - Setting CLICommand class attribute for framework registration Signed-off-by: Kefu Chai <k.chai@proxmox.com>
Fixes: https://tracker.ceph.com/issues/74042
Show available Jenkins commands
jenkins test classic perfJenkins Job | Jenkins Job Definitionjenkins test crimson perfJenkins Job | Jenkins Job Definitionjenkins test signedJenkins Job | Jenkins Job Definitionjenkins test make checkJenkins Job | Jenkins Job Definitionjenkins test make check arm64Jenkins Job | Jenkins Job Definitionjenkins test submodulesJenkins Job | Jenkins Job Definitionjenkins test dashboardJenkins Job | Jenkins Job Definitionjenkins test dashboard cephadmJenkins Job | Jenkins Job Definitionjenkins test apiJenkins Job | Jenkins Job Definitionjenkins test docsReadTheDocs | Github Workflow Definitionjenkins test ceph-volume allJenkins Jobs | Jenkins Jobs Definitionjenkins test windowsJenkins Job | Jenkins Job Definitionjenkins test rook e2eJenkins Job | Jenkins Job DefinitionYou must only issue one Jenkins command per-comment. Jenkins does not understand
comments with more than one command.