]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/mgr/smb: add proto.py for protcol classes and generic types
authorJohn Mulligan <jmulligan@redhat.com>
Tue, 30 Jan 2024 19:39:16 +0000 (14:39 -0500)
committerJohn Mulligan <jmulligan@redhat.com>
Thu, 25 Apr 2024 23:10:38 +0000 (19:10 -0400)
Signed-off-by: John Mulligan <jmulligan@redhat.com>
src/pybind/mgr/smb/proto.py [new file with mode: 0644]

diff --git a/src/pybind/mgr/smb/proto.py b/src/pybind/mgr/smb/proto.py
new file mode 100644 (file)
index 0000000..96aed6c
--- /dev/null
@@ -0,0 +1,177 @@
+"""Assorted protocols/interfaces and types used in the smb mgr module."""
+
+from typing import (
+    TYPE_CHECKING,
+    Any,
+    Collection,
+    Dict,
+    Iterator,
+    List,
+    Optional,
+    Tuple,
+    TypeVar,
+)
+
+import sys
+
+from ceph.deployment.service_spec import SMBSpec
+
+# 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
+elif TYPE_CHECKING:  # pragma: no cover
+    # typing_extensions will not be available for the real mgr server
+    from typing_extensions import Protocol
+else:  # pragma: no cover
+    # fallback type that is acceptable to older python on prod. builds
+    class Protocol:  # type: ignore
+        pass
+
+
+if sys.version_info >= (3, 11):
+    from typing import Self
+elif TYPE_CHECKING:  # pragma: no cover
+    # typing_extensions will not be available for the real mgr server
+    from typing_extensions import Self
+else:  # pragma: no cover
+    # fallback type that should be ignored at runtime
+    Self = Any  # type: ignore
+
+
+Simplified = Dict[str, Any]
+SimplifiedList = List[Simplified]
+
+
+class Simplifiable(Protocol):
+    def to_simplified(self) -> Simplified:
+        ...  # pragma: no cover
+
+
+EntryKey = Tuple[str, str]
+
+
+class ConfigEntry(Protocol):
+    """A protocol for describing a configuration object that can be kept within
+    a configuration store. Has the ability to identify itself either by a
+    relative key or by a global URI value.
+    """
+
+    def get(self) -> Simplified:
+        ...  # pragma: no cover
+
+    def set(self, obj: Simplified) -> None:
+        ...  # pragma: no cover
+
+    def remove(self) -> bool:
+        ...  # pragma: no cover
+
+    def exists(self) -> bool:
+        ...  # pragma: no cover
+
+    @property
+    def uri(self) -> str:
+        ...  # pragma: no cover
+
+    @property
+    def full_key(self) -> EntryKey:
+        ...  # pragma: no cover
+
+
+class ConfigStore(Protocol):
+    """A protocol for describing a configuration data store capable of
+    retaining and tracking configuration entry objects.
+    """
+
+    def __getitem__(self, key: EntryKey) -> ConfigEntry:
+        ...  # pragma: no cover
+
+    def namespaces(self) -> Collection[str]:
+        ...  # pragma: no cover
+
+    def contents(self, ns: str) -> Collection[str]:
+        ...  # pragma: no cover
+
+    def __iter__(self) -> Iterator[EntryKey]:
+        ...  # pragma: no cover
+
+    def remove(self, ns: EntryKey) -> bool:
+        ...  # pragma: no cover
+
+
+class PathResolver(Protocol):
+    """A protocol describing a type that can map volumes, subvolumes, and
+    paths to real paths within a cephfs system.
+    """
+
+    def resolve(
+        self, volume: str, subvolumegroup: str, subvolume: str, path: str
+    ) -> str:
+        """Return the path within the volume for the given subvolume and path.
+        No other checking is performed.
+        """
+        ...  # pragma: no cover
+
+    def resolve_exists(
+        self, volume: str, subvolumegroup: str, subvolume: str, path: str
+    ) -> str:
+        """Return the path within the volume for the given subvolume and path.
+        Raises an exception if the path does not exist or is not a directory.
+        """
+        ...  # pragma: no cover
+
+
+class OrchSubmitter(Protocol):
+    """A protocol describing a type that can submit a SMBSpec to ceph's
+    orchestration system.
+    """
+
+    def submit_smb_spec(self, smb_spec: SMBSpec) -> None:
+        ...  # pragma: no cover
+
+    def remove_smb_service(self, service_name: str) -> None:
+        ...  # pragma: no cover
+
+
+class MonCommandIssuer(Protocol):
+    """A protocol describing the minimal interface that can issue mon commands."""
+
+    def mon_command(
+        self, cmd_dict: dict, inbuf: Optional[str] = None
+    ) -> Tuple[int, str, str]:
+        ...  # pragma: no cover
+
+
+class AccessAuthorizer(Protocol):
+    """A protocol for a type that can requrest cephx caps needed for file
+    system access.
+    """
+
+    def authorize_entity(
+        self, volume: str, entity: str, caps: str = ''
+    ) -> None:
+        ...  # pragma: no cover
+
+
+T = TypeVar('T')
+
+
+# TODO: move to a utils.py
+def one(lst: List[T]) -> T:
+    if len(lst) != 1:
+        raise ValueError("list does not contain exactly one element")
+    return lst[0]
+
+
+class IsNoneError(ValueError):
+    pass
+
+
+def checked(v: Optional[T]) -> T:
+    """Ensures the provided value is not a None or raises a IsNoneError.
+    Intended use is similar to an `assert v is not None` but more usable in
+    one-liners and list/dict/etc comprehensions.
+    """
+    if v is None:
+        raise IsNoneError('value is None')
+    return v