]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
pybind/mgr/smb: add internal.py intermediate funcs for internal config store
authorJohn Mulligan <jmulligan@redhat.com>
Fri, 2 Feb 2024 00:42:21 +0000 (19:42 -0500)
committerJohn Mulligan <jmulligan@redhat.com>
Thu, 25 Apr 2024 23:10:39 +0000 (19:10 -0400)
Signed-off-by: John Mulligan <jmulligan@redhat.com>
src/pybind/mgr/smb/internal.py [new file with mode: 0644]

diff --git a/src/pybind/mgr/smb/internal.py b/src/pybind/mgr/smb/internal.py
new file mode 100644 (file)
index 0000000..d40561b
--- /dev/null
@@ -0,0 +1,166 @@
+"""Support for working with the internal data store and the strucutured
+resources that the internal store holds.
+"""
+from typing import Collection, Tuple, Type, TypeVar
+
+from . import resources
+from .enums import AuthMode, ConfigNS, State
+from .proto import ConfigEntry, ConfigStore, Self, Simplifiable, one
+from .resources import SMBResource
+from .results import ErrorResult
+
+T = TypeVar('T')
+
+
+class ResourceEntry:
+    """Base class for resource entry getter/setter objects."""
+
+    namespace: ConfigNS
+
+    def __init__(self, key: str, config_entry: ConfigEntry) -> None:
+        self.key = key
+        self.config_entry = config_entry
+
+    @property
+    def uri(self) -> str:
+        return self.config_entry.uri
+
+    def get(self) -> SMBResource:
+        return one(resources.load(self.config_entry.get()))
+
+    def get_resource_type(self, cls: Type[T]) -> T:
+        obj = self.get()
+        assert isinstance(obj, cls)
+        return obj
+
+    def set(self, resource: Simplifiable) -> None:
+        self.config_entry.set(resource.to_simplified())
+
+    def create_or_update(self, resource: Simplifiable) -> State:
+        try:
+            previous = self.config_entry.get()
+        except KeyError:
+            previous = None
+        current = resource.to_simplified()
+        if current == previous:
+            return State.PRESENT
+        self.config_entry.set(current)
+        return State.CREATED if previous is None else State.UPDATED
+
+    def remove(self) -> bool:
+        return self.config_entry.remove()
+
+
+class ClusterEntry(ResourceEntry):
+    """Cluster resource getter/setter for the smb internal data store(s)."""
+
+    namespace = ConfigNS.CLUSTERS
+
+    @classmethod
+    def from_store(cls, store: ConfigStore, cluster_id: str) -> Self:
+        return cls(cluster_id, store[str(cls.namespace), cluster_id])
+
+    @classmethod
+    def ids(cls, store: ConfigStore) -> Collection[str]:
+        return store.contents(str(cls.namespace))
+
+    def get_cluster(self) -> resources.Cluster:
+        return self.get_resource_type(resources.Cluster)
+
+    def create_or_update(self, resource: Simplifiable) -> State:
+        assert isinstance(resource, resources.Cluster)
+        try:
+            previous = self.config_entry.get()
+        except KeyError:
+            previous = None
+        current = resource.to_simplified()
+        if current == previous:
+            return State.PRESENT
+        elif previous is None:
+            self.config_entry.set(current)
+            return State.CREATED
+        # cluster is special in that is has some fields that we do not
+        # permit changing.
+        prev = getattr(
+            resources.Cluster, '_resource_config'
+        ).object_from_simplified(previous)
+        if resource.auth_mode != prev.auth_mode:
+            raise ErrorResult(
+                resource,
+                'auth_mode value may not be changed',
+                status={'existing_auth_mode': prev.auth_mode},
+            )
+        if resource.auth_mode == AuthMode.ACTIVE_DIRECTORY:
+            assert resource.domain_settings
+            assert prev.domain_settings
+            if resource.domain_settings.realm != prev.domain_settings.realm:
+                raise ErrorResult(
+                    resource,
+                    'domain/realm value may not be changed',
+                    status={
+                        'existing_domain_realm': prev.domain_settings.realm
+                    },
+                )
+        self.config_entry.set(current)
+        return State.UPDATED
+
+
+class ShareEntry(ResourceEntry):
+    """Share resource getter/setter for the smb internal data store(s)."""
+
+    namespace = ConfigNS.SHARES
+
+    @classmethod
+    def from_store(
+        cls, store: ConfigStore, cluster_id: str, share_id: str
+    ) -> Self:
+        key = f'{cluster_id}.{share_id}'
+        return cls(key, store[str(cls.namespace), key])
+
+    @classmethod
+    def ids(cls, store: ConfigStore) -> Collection[Tuple[str, str]]:
+        return [_split(k) for k in store.contents(str(cls.namespace))]
+
+    def get_share(self) -> resources.Share:
+        return self.get_resource_type(resources.Share)
+
+
+class JoinAuthEntry(ResourceEntry):
+    """JoinAuth resource getter/setter for the smb internal data store(s)."""
+
+    namespace = ConfigNS.JOIN_AUTHS
+
+    @classmethod
+    def from_store(cls, store: ConfigStore, auth_id: str) -> Self:
+        return cls(auth_id, store[str(cls.namespace), auth_id])
+
+    @classmethod
+    def ids(cls, store: ConfigStore) -> Collection[str]:
+        return store.contents(str(cls.namespace))
+
+    def get_join_auth(self) -> resources.JoinAuth:
+        return self.get_resource_type(resources.JoinAuth)
+
+
+class UsersAndGroupsEntry(ResourceEntry):
+    """UsersAndGroupsEntry resource getter/setter for the smb internal data
+    store(s).
+    """
+
+    namespace = ConfigNS.USERS_AND_GROUPS
+
+    @classmethod
+    def from_store(cls, store: ConfigStore, auth_id: str) -> Self:
+        return cls(auth_id, store[str(cls.namespace), auth_id])
+
+    @classmethod
+    def ids(cls, store: ConfigStore) -> Collection[str]:
+        return store.contents(str(cls.namespace))
+
+    def get_users_and_groups(self) -> resources.UsersAndGroups:
+        return self.get_resource_type(resources.UsersAndGroups)
+
+
+def _split(share_key: str) -> Tuple[str, str]:
+    cluster_id, share_id = share_key.split('.', 1)
+    return cluster_id, share_id