]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/mgr: enhance CLICommand to fetch extra args from wrapped funcs
authorJohn Mulligan <jmulligan@redhat.com>
Mon, 11 Apr 2022 19:03:12 +0000 (15:03 -0400)
committerAdam King <adking@redhat.com>
Sat, 21 May 2022 23:21:42 +0000 (19:21 -0400)
Previously, the CLICommand decorator "assumed" that the decorator was
applied directly to a mgr module api endpoint function. Now that we plan
on adding the Responder decorator into the mix we need a way of
properly fetching the arguments of the endpoint function. In addition,
the decorator itself needs to provide extra arguments to the mgr
(in cases where the endpoint function doesn't explicitly ask for it).
Thus we add a helper function to find the endpoint function when
wrapped as well as extract extra arguments when "walking" the stack
of __wrapped__ functions.

Signed-off-by: John Mulligan <jmulligan@redhat.com>
(cherry picked from commit 2b22297f5664a2c778f6591dd1e1f3822fc5a3c1)

src/pybind/mgr/mgr_module.py

index f8f85b7172d82ce19bffeca327e3ed36c6f9b9f6..9110227efcc9d14b3b0f956c9455edb583a6c5ce 100644 (file)
@@ -329,6 +329,26 @@ class CRUSHMap(ceph_module.BasePyCRUSH):
 
 HandlerFuncType = Callable[..., Tuple[int, str, str]]
 
+def _extract_target_func(
+    f: HandlerFuncType
+) -> Tuple[HandlerFuncType, Dict[str, Any]]:
+    """In order to interoperate with other decorated functions,
+    we need to find the original function which will provide
+    the main set of arguments. While we descend through the
+    stack of wrapped functions, gather additional arguments
+    the decorators may want to provide.
+    """
+    # use getattr to keep mypy happy
+    wrapped = getattr(f, "__wrapped__", None)
+    if not wrapped:
+        return f, {}
+    extra_args = {}
+    while wrapped is not None:
+        extra_args.update(getattr(f, "extra_args", {}))
+        f = wrapped
+        wrapped = getattr(f, "__wrapped__", None)
+    return f, extra_args
+
 
 class CLICommand(object):
     COMMANDS = {}  # type: Dict[str, CLICommand]
@@ -348,6 +368,7 @@ class CLICommand(object):
 
     @classmethod
     def _load_func_metadata(cls: Any, f: HandlerFuncType) -> Tuple[str, Dict[str, Any], int, str]:
+        f, extra_args = _extract_target_func(f)
         desc = (inspect.getdoc(f) or '').replace('\n', ' ')
         full_argspec = inspect.getfullargspec(f)
         arg_spec = full_argspec.annotations
@@ -377,6 +398,14 @@ class CLICommand(object):
                                                dict(name=arg),
                                                has_default,
                                                positional))
+        for argname, argtype in extra_args.items():
+            # avoid shadowing args from the function
+            if argname in arg_spec:
+                continue
+            arg_spec[argname] = argtype
+            args.append(CephArgtype.to_argdesc(
+                argtype, dict(name=arg), has_default=True, positional=False
+            ))
         return desc, arg_spec, first_default, ' '.join(args)
 
     def store_func_metadata(self, f: HandlerFuncType) -> None: