]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
mgr/orchestrator: Use CLICommand, except it's global variable
authorSebastian Wagner <sebastian.wagner@suse.com>
Wed, 12 Feb 2020 15:21:05 +0000 (16:21 +0100)
committerSebastian Wagner <sebastian.wagner@suse.com>
Mon, 17 Feb 2020 09:24:01 +0000 (10:24 +0100)
`CLICommand.COMMANDS` is a global varialbe that prevents
anyone from importing other modules, as the `COMMANS` are then
merged together. Let's use a meta class instead of a global variable.

Signed-off-by: Sebastian Wagner <sebastian.wagner@suse.com>
src/pybind/mgr/cephadm/module.py
src/pybind/mgr/mgr_module.py
src/pybind/mgr/orchestrator/__init__.py
src/pybind/mgr/orchestrator/_interface.py
src/pybind/mgr/orchestrator/module.py

index 66d9ccad1988accdd975c7436a2895fcb1d97be9..a64d046315e4dea67a16bc1498fa09ab2b47c257 100644 (file)
@@ -30,7 +30,8 @@ from ceph.deployment.drive_selection import selector
 from mgr_module import MgrModule
 import mgr_util
 import orchestrator
-from orchestrator import OrchestratorError, HostPlacementSpec, OrchestratorValidationError, HostSpec
+from orchestrator import OrchestratorError, HostPlacementSpec, OrchestratorValidationError, HostSpec, \
+    CLICommandMeta
 
 from . import remotes
 
@@ -284,6 +285,7 @@ def with_daemons(daemon_type=None,
         return wrapper
     return decorator
 
+@six.add_metaclass(CLICommandMeta)
 class CephadmOrchestrator(MgrModule, orchestrator.OrchestratorClientMixin):
 
     _STORE_HOST_PREFIX = "host"
index 8cd4bbe39242e8c05d994d630dcb3342b1e74b99..1681e7c998ae3fcd17a8fc7a91c0d8eae61e4812 100644 (file)
@@ -308,13 +308,16 @@ class CLICommand(object):
         assert self.func
         return self.func(mgr, **kwargs)
 
+    def dump_cmd(self):
+        return {
+            'cmd': '{} {}'.format(self.prefix, self.args),
+            'desc': self.desc,
+            'perm': self.perm
+        }
+
     @classmethod
     def dump_cmd_list(cls):
-        return [{
-            'cmd': '{} {}'.format(cmd.prefix, cmd.args),
-            'desc': cmd.desc,
-            'perm': cmd.perm
-        } for _, cmd in cls.COMMANDS.items()]
+        return [cmd.dump_cmd() for cmd in cls.COMMANDS.values()]
 
 
 def CLIReadCommand(prefix, args="", desc=""):
index 946ddb058676a96c2a31358ce566d12756f75c04..857d4b5ffc0c37dd238963587310705d8723d465 100644 (file)
@@ -5,7 +5,7 @@ from .module import OrchestratorCli
 # usage: E.g. `from orchestrator import StatelessServiceSpec`
 from ._interface import \
     Completion, TrivialReadCompletion, raise_if_exception, ProgressReference, pretty_print, _Promise, \
-    CLICommand, _cli_write_command, _cli_read_command, \
+    CLICommand, _cli_write_command, _cli_read_command, CLICommandMeta, \
     Orchestrator, OrchestratorClientMixin, \
     OrchestratorValidationError, OrchestratorError, NoOrchestrator, \
     ServiceSpec, NFSServiceSpec, RGWSpec, HostPlacementSpec, \
index 1a9114647265db3866af035587c3a66a503aa628..8901c4a9c1fb38bba93d3dc5151593e28f6293dc 100644 (file)
@@ -11,7 +11,7 @@ import pickle
 import sys
 import time
 from collections import namedtuple
-from functools import wraps
+from functools import wraps, partial
 import uuid
 import string
 import random
@@ -29,7 +29,7 @@ from mgr_util import format_bytes
 try:
     from ceph.deployment.drive_group import DriveGroupSpec
     from typing import TypeVar, Generic, List, Optional, Union, Tuple, Iterator, Callable, Any, \
-        Type, Sequence
+        Type, Sequence, Dict
 except ImportError:
     pass
 
@@ -148,7 +148,13 @@ def handle_exception(prefix, cmd_args, desc, perm, func):
             msg = 'This Orchestrator does not support `{}`'.format(prefix)
             return HandleCommandResult(-errno.ENOENT, stderr=msg)
 
-    return CLICommand(prefix, cmd_args, desc, perm)(wrapper)
+    # misuse partial to copy `wrapper`
+    wrapper_copy = partial(wrapper)
+    wrapper_copy._prefix = prefix  # type: ignore
+    wrapper_copy._cli_command = CLICommand(prefix, cmd_args, desc, perm)  # type: ignore
+    wrapper_copy._cli_command.func = wrapper_copy  # type: ignore
+
+    return wrapper_copy
 
 
 def _cli_command(perm):
@@ -161,6 +167,32 @@ _cli_read_command = _cli_command('r')
 _cli_write_command = _cli_command('rw')
 
 
+class CLICommandMeta(type):
+    """
+    This is a workaround for the use of a global variable CLICommand.COMMANDS which
+    prevents modules from importing any other module.
+
+    We make use of CLICommand, except for the use of the global variable.
+    """
+    def __init__(cls, name, bases, dct):
+        super(CLICommandMeta, cls).__init__(name, bases, dct)
+        dispatch = {}  # type: Dict[str, CLICommand]
+        for v in dct.values():
+            try:
+                dispatch[v._prefix] = v._cli_command
+            except AttributeError:
+                pass
+
+        def handle_command(self, inbuf, cmd):
+            if cmd['prefix'] not in dispatch:
+                return self.handle_command(inbuf, cmd)
+
+            return dispatch[cmd['prefix']].call(self, cmd, inbuf)
+
+        cls.COMMANDS = [cmd.dump_cmd() for cmd in dispatch.values()]
+        cls.handle_command = handle_command
+
+
 def _no_result():
     return object()
 
index 277743fb7a0849017c3a4c685d3c119cf9d0fad1..7dd39931973caf5f1e005ef3475f02070afa8e75 100644 (file)
@@ -3,13 +3,15 @@ import errno
 import json
 import yaml
 
+import six
+
 from ceph.deployment.inventory import Device
 from prettytable import PrettyTable
 
 from mgr_util import format_bytes, to_pretty_timedelta
 
 try:
-    from typing import List, Set, Optional
+    from typing import List, Set, Optional, Dict
 except ImportError:
     pass  # just for type checking.
 
@@ -21,9 +23,10 @@ from mgr_module import MgrModule, HandleCommandResult
 from ._interface import OrchestratorClientMixin, DeviceLightLoc, _cli_read_command, \
     raise_if_exception, _cli_write_command, TrivialReadCompletion, OrchestratorError, \
     NoOrchestrator, ServiceSpec, PlacementSpec, OrchestratorValidationError, NFSServiceSpec, \
-    RGWSpec, InventoryFilter, InventoryNode, HostPlacementSpec, HostSpec
+    RGWSpec, InventoryFilter, InventoryNode, HostPlacementSpec, HostSpec, CLICommandMeta
 
 
+@six.add_metaclass(CLICommandMeta)
 class OrchestratorCli(OrchestratorClientMixin, MgrModule):
     MODULE_OPTIONS = [
         {