]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/rgw: Adding typing checks for rgw
authorRedouane Kachach <rkachach@redhat.com>
Wed, 19 Oct 2022 07:59:12 +0000 (09:59 +0200)
committerAdam King <adking@redhat.com>
Wed, 5 Apr 2023 17:34:10 +0000 (13:34 -0400)
Fixes: https://tracker.ceph.com/issues/57878
Signed-off-by: Redouane Kachach <rkachach@redhat.com>
(cherry picked from commit c6f05d8debea12aa5f536627074642186b9b4059)

Conflicts:
src/pybind/mgr/tox.ini

src/pybind/mgr/rgw/__init__.py
src/pybind/mgr/rgw/module.py
src/pybind/mgr/tox.ini
src/python-common/ceph/rgw/types.py

index 081f4c7d85dd84613031a2710beb3ff5453c7cf0..ee85dc9d376e61235d719cf25585769bd07299a6 100644 (file)
@@ -1,5 +1,2 @@
 # flake8: noqa
-try:
-    from .module import Module
-except ImportError:
-    pass
+from .module import Module
index 1f87481a7c6448f5618c96356e4d20ec8715b231..d1fc1420eb7af8e54d99ae601bfd23a7b7feaa2d 100644 (file)
@@ -4,16 +4,43 @@ import yaml
 import errno
 import base64
 import functools
+import sys
 
-from mgr_module import MgrModule, CLICommand, HandleCommandResult
+from mgr_module import MgrModule, CLICommand, HandleCommandResult, Option
 import orchestrator
 
 from ceph.deployment.service_spec import RGWSpec, PlacementSpec, SpecValidationError
-from typing import Any, Optional, Sequence, Iterator, List
+from typing import Any, Optional, Sequence, Iterator, List, Callable, TypeVar, cast, Dict, Tuple, Union
 
 from ceph.rgw.types import RGWAMException, RGWAMEnvMgr, RealmToken
 from ceph.rgw.rgwam_core import EnvArgs, RGWAM
-from orchestrator import OrchestratorClientMixin, OrchestratorError
+from orchestrator import OrchestratorClientMixin, OrchestratorError, DaemonDescription, OrchResult
+
+
+FuncT = TypeVar('FuncT', bound=Callable[..., Any])
+
+# this uses a version check as opposed to a try/except because this
+# form makes mypy happy and try/except doesn't.
+if sys.version_info >= (3, 8):
+    from typing import Protocol
+else:
+    # typing_extensions will not be available for the real mgr server
+    from typing_extensions import Protocol
+
+
+class MgrModuleProtocol(Protocol):
+    def tool_exec(self, args: List[str]) -> Tuple[int, str, str]:
+        ...
+
+    def apply_rgw(self, spec: RGWSpec) -> OrchResult[str]:
+        ...
+
+    def list_daemons(self, service_name: Optional[str] = None,
+                     daemon_type: Optional[str] = None,
+                     daemon_id: Optional[str] = None,
+                     host: Optional[str] = None,
+                     refresh: bool = False) -> OrchResult[List['DaemonDescription']]:
+        ...
 
 
 class RGWSpecParsingError(Exception):
@@ -21,11 +48,11 @@ class RGWSpecParsingError(Exception):
 
 
 class OrchestratorAPI(OrchestratorClientMixin):
-    def __init__(self, mgr):
+    def __init__(self, mgr: MgrModule):
         super(OrchestratorAPI, self).__init__()
-        self.set_mgr(mgr)  # type: ignore
+        self.set_mgr(mgr)
 
-    def status(self):
+    def status(self) -> Dict[str, Union[str, bool]]:
         try:
             status, message, _module_details = super().available()
             return dict(available=status, message=message)
@@ -34,19 +61,23 @@ class OrchestratorAPI(OrchestratorClientMixin):
 
 
 class RGWAMOrchMgr(RGWAMEnvMgr):
-    def __init__(self, mgr):
+    def __init__(self, mgr: MgrModuleProtocol):
         self.mgr = mgr
 
-    def tool_exec(self, prog, args):
+    def tool_exec(self, prog: str, args: List[str]) -> Tuple[List[str], int, str, str]:
         cmd = [prog] + args
         rc, stdout, stderr = self.mgr.tool_exec(args=cmd)
         return cmd, rc, stdout, stderr
 
-    def apply_rgw(self, spec):
+    def apply_rgw(self, spec: RGWSpec) -> None:
         completion = self.mgr.apply_rgw(spec)
         orchestrator.raise_if_exception(completion)
 
-    def list_daemons(self, service_name, daemon_type=None, daemon_id=None, host=None, refresh=True):
+    def list_daemons(self, service_name: Optional[str] = None,
+                     daemon_type: Optional[str] = None,
+                     daemon_id: Optional[str] = None,
+                     host: Optional[str] = None,
+                     refresh: bool = True) -> List['DaemonDescription']:
         completion = self.mgr.list_daemons(service_name,
                                            daemon_type,
                                            daemon_id=daemon_id,
@@ -55,11 +86,23 @@ class RGWAMOrchMgr(RGWAMEnvMgr):
         return orchestrator.raise_if_exception(completion)
 
 
+def check_orchestrator(func: FuncT) -> FuncT:
+    @functools.wraps(func)
+    def wrapper(self: Any, *args: Any, **kwargs: Any) -> HandleCommandResult:
+        available = self.api.status()['available']
+        if available:
+            return func(self, *args, **kwargs)
+        else:
+            err_msg = "Cephadm is not available. Please enable cephadm by 'ceph mgr module enable cephadm'."
+            return HandleCommandResult(retval=-errno.EINVAL, stdout='', stderr=err_msg)
+    return cast(FuncT, wrapper)
+
+
 class Module(orchestrator.OrchestratorClientMixin, MgrModule):
-    MODULE_OPTIONS = []
+    MODULE_OPTIONS: List[Option] = []
 
     # These are "native" Ceph options that this module cares about.
-    NATIVE_OPTIONS = []
+    NATIVE_OPTIONS: List[Option] = []
 
     def __init__(self, *args: Any, **kwargs: Any):
         self.inited = False
@@ -94,25 +137,12 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         # Do the same for the native options.
         for opt in self.NATIVE_OPTIONS:
             setattr(self,
-                    opt,
+                    opt,  # type: ignore
                     self.get_ceph_option(opt))
-            self.log.debug(' native option %s = %s', opt, getattr(self, opt))
-
-    def check_orchestrator():
-        def inner(func):
-            @functools.wraps(func)
-            def wrapper(self, *args, **kwargs):
-                available = self.api.status()['available']
-                if available:
-                    return func(self, *args, **kwargs)
-                else:
-                    err_msg = "Orchestrator is not available. Please enable cephadm by 'ceph mgr module enable cephadm'."
-                    return HandleCommandResult(retval=-errno.EINVAL, stdout='', stderr=err_msg)
-            return wrapper
-        return inner
+            self.log.debug(' native option %s = %s', opt, getattr(self, opt))  # type: ignore
 
     @CLICommand('rgw admin', perm='rw')
-    def _cmd_rgw_admin(self, params: Sequence[str]):
+    def _cmd_rgw_admin(self, params: Sequence[str]) -> HandleCommandResult:
         """rgw admin"""
         cmd, returncode, out, err = self.env.mgr.tool_exec('radosgw-admin', params or [])
 
@@ -123,7 +153,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         return HandleCommandResult(retval=returncode, stdout=out, stderr=err)
 
     @CLICommand('rgw realm bootstrap', perm='rw')
-    @check_orchestrator()
+    @check_orchestrator
     def _cmd_rgw_realm_bootstrap(self,
                                  realm_name: Optional[str] = None,
                                  zonegroup_name: Optional[str] = None,
@@ -132,7 +162,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                  placement: Optional[str] = None,
                                  zone_endpoints: Optional[str] = None,
                                  start_radosgw: Optional[bool] = True,
-                                 inbuf: Optional[str] = None):
+                                 inbuf: Optional[str] = None) -> HandleCommandResult:
         """Bootstrap new rgw realm, zonegroup, and zone"""
 
         if inbuf:
@@ -161,7 +191,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
 
         return HandleCommandResult(retval=0, stdout="Realm(s) created correctly. Please, use 'ceph rgw realm tokens' to get the token.", stderr='')
 
-    def _parse_rgw_specs(self, inbuf: Optional[str] = None) -> List[RGWSpec]:
+    def _parse_rgw_specs(self, inbuf: str) -> List[RGWSpec]:
         """Parse RGW specs from a YAML file."""
         # YAML '---' document separator with no content generates
         # None entries in the output. Let's skip them silently.
@@ -191,7 +221,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
     def _cmd_rgw_realm_new_zone_creds(self,
                                       realm_name: Optional[str] = None,
                                       endpoints: Optional[str] = None,
-                                      sys_uid: Optional[str] = None):
+                                      sys_uid: Optional[str] = None) -> HandleCommandResult:
         """Create credentials for new zone creation"""
 
         try:
@@ -203,7 +233,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         return HandleCommandResult(retval=retval, stdout=out, stderr=err)
 
     @CLICommand('rgw realm zone-creds remove', perm='rw')
-    def _cmd_rgw_realm_rm_zone_creds(self, realm_token: Optional[str] = None):
+    def _cmd_rgw_realm_rm_zone_creds(self, realm_token: Optional[str] = None) -> HandleCommandResult:
         """Create credentials for new zone creation"""
 
         try:
@@ -215,7 +245,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         return HandleCommandResult(retval=retval, stdout=out, stderr=err)
 
     @CLICommand('rgw realm tokens', perm='r')
-    def list_realm_tokens(self):
+    def list_realm_tokens(self) -> HandleCommandResult:
         try:
             realms_info = []
             for realm_info in RGWAM(self.env).get_realms_info():
@@ -238,20 +268,20 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
         return HandleCommandResult(retval=0, stdout=json.dumps(realms_info, indent=4), stderr='')
 
     @CLICommand('rgw zone modify', perm='rw')
-    def update_zone_info(self, realm_name: str, zonegroup_name: str, zone_name: str, realm_token: str, zone_endpoints: List[str]):
+    def update_zone_info(self, realm_name: str, zonegroup_name: str, zone_name: str, realm_token: str, zone_endpoints: List[str]) -> HandleCommandResult:
         try:
             retval, out, err = RGWAM(self.env).zone_modify(realm_name,
                                                            zonegroup_name,
                                                            zone_name,
                                                            zone_endpoints,
                                                            realm_token)
-            return (retval, 'Zone updated successfully', '')
+            return HandleCommandResult(retval, 'Zone updated successfully', '')
         except RGWAMException as e:
             self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message))
             return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr)
 
     @CLICommand('rgw zone create', perm='rw')
-    @check_orchestrator()
+    @check_orchestrator
     def _cmd_rgw_zone_create(self,
                              zone_name: Optional[str] = None,
                              realm_token: Optional[str] = None,
@@ -259,7 +289,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                              placement: Optional[str] = None,
                              start_radosgw: Optional[bool] = True,
                              zone_endpoints: Optional[str] = None,
-                             inbuf: Optional[str] = None):
+                             inbuf: Optional[str] = None) -> HandleCommandResult:
         """Bootstrap new rgw zone that syncs with zone on another cluster in the same realm"""
 
         if inbuf:
@@ -284,7 +314,8 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
             created_zones = []
             for rgw_spec in rgw_specs:
                 RGWAM(self.env).zone_create(rgw_spec, start_radosgw)
-                created_zones.append(rgw_spec.rgw_zone)
+                if rgw_spec.rgw_zone is not None:
+                    created_zones.append(rgw_spec.rgw_zone)
         except RGWAMException as e:
             self.log.error('cmd run exception: (%d) %s' % (e.retcode, e.message))
             return HandleCommandResult(retval=e.retcode, stdout=e.stdout, stderr=e.stderr)
@@ -296,7 +327,7 @@ class Module(orchestrator.OrchestratorClientMixin, MgrModule):
                                  realm_name: Optional[str] = None,
                                  zonegroup_name: Optional[str] = None,
                                  zone_name: Optional[str] = None,
-                                 update: Optional[bool] = False):
+                                 update: Optional[bool] = False) -> HandleCommandResult:
         """Bootstrap new rgw zone that syncs with existing zone"""
 
         try:
index d6ae7a29b3d63074331669e7ac2d298a7e310d0d..a96321c1c78a4221e3416ecc1dfeecd773799645 100644 (file)
@@ -103,6 +103,7 @@ commands =
            -m progress \
            -m prometheus \
            -m rbd_support \
+          -m rgw \
            -m rook \
            -m snap_schedule \
            -m selftest \
@@ -136,6 +137,7 @@ modules =
     nfs \
     orchestrator \
     prometheus \
+    rgw \
     status \
     telemetry
 commands =
@@ -171,6 +173,7 @@ modules =
     nfs \
     orchestrator \
     prometheus \
+    rgw \
     selftest
 commands =
     flake8 --config=tox.ini {posargs} \
index 4a69e6a7f88954a2a95b9b1b96aab0433fdcd214..3f65f9da00e0f4b97e2b47e7c0f12234e625e47d 100644 (file)
@@ -35,7 +35,7 @@ class RGWAMEnvMgr:
         pass
 
     @abstractmethod
-    def apply_rgw(self, svc_id, realm_name, zone_name, port=None):
+    def apply_rgw(self, spec):
         pass
 
     @abstractmethod