From c6648cb0a2f9adc1061aac7d49b737e8ec8ed346 Mon Sep 17 00:00:00 2001 From: John Mulligan Date: Tue, 30 Jan 2024 14:39:16 -0500 Subject: [PATCH] pybind/mgr/smb: add config_store.py defining generic in-memory stores The config store abstraction is defined in proto.py the config_store.py configuration stores meet this protocol with wrappers around in memory structures. Signed-off-by: John Mulligan --- src/pybind/mgr/smb/config_store.py | 99 ++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 src/pybind/mgr/smb/config_store.py diff --git a/src/pybind/mgr/smb/config_store.py b/src/pybind/mgr/smb/config_store.py new file mode 100644 index 0000000000000..17cae3af44ec0 --- /dev/null +++ b/src/pybind/mgr/smb/config_store.py @@ -0,0 +1,99 @@ +from typing import Collection, Dict, Iterator + +from .proto import ConfigEntry, EntryKey, Simplified + + +class MemConfigEntry: + """A simple in-memory config store entry. Meant only for testing. + Objects are not serialized like most other stores. + """ + + def __init__(self, store: 'MemConfigStore', ns: str, name: str) -> None: + self._store = store + self._ns = ns + self._name = name + + def set(self, obj: Simplified) -> None: + self._store._data[(self._ns, self._name)] = obj + + def get(self) -> Simplified: + return self._store._data[(self._ns, self._name)] + + def remove(self) -> bool: + return self._store.remove(self.full_key) + + def exists(self) -> bool: + return (self._ns, self._name) in self._store._data + + @property + def uri(self) -> str: + return f'mem:{self._ns}/{self._name}' + + @property + def full_key(self) -> EntryKey: + return (self._ns, self._name) + + +class MemConfigStore: + """A simple in-memory config store. Meant only for testing.""" + + def __init__(self) -> None: + self._data: Dict[EntryKey, Simplified] = {} + + def __getitem__(self, key: EntryKey) -> MemConfigEntry: + return MemConfigEntry(self, key[0], key[1]) + + def remove(self, key: EntryKey) -> bool: + return self._data.pop(key, None) is not None + + def namespaces(self) -> Collection[str]: + return {k[0] for k in self._data.keys()} + + def contents(self, ns: str) -> Collection[str]: + return [k[1] for k in self._data.keys() if k[0] == ns] + + def __iter__(self) -> Iterator[EntryKey]: + return iter(self._data.keys()) + + # for testing only + def overwrite(self, data: Simplified) -> None: + self._data = {} + for key, value in data.items(): + if isinstance(key, str): + keyns, keyname = key.split('.', 1) + else: + keyns, keyname = key + self._data[(keyns, keyname)] = value + + # for testing only + @property + def data(self) -> Dict[EntryKey, Simplified]: + return self._data + + +class EntryCache: + """An in-memory cache compatible with the ConfigStore interface. It should + be used to cache *existing* ConfigEntry objects produced by/for other + stores. + """ + + def __init__(self) -> None: + self._entries: Dict[EntryKey, ConfigEntry] = {} + + def __getitem__(self, key: EntryKey) -> ConfigEntry: + return self._entries[key] + + def __setitem__(self, key: EntryKey, value: ConfigEntry) -> None: + self._entries[key] = value + + def remove(self, key: EntryKey) -> bool: + return self._entries.pop(key, None) is not None + + def namespaces(self) -> Collection[str]: + return {k[0] for k in self} + + def contents(self, ns: str) -> Collection[str]: + return [kname for kns, kname in self if ns == ns] + + def __iter__(self) -> Iterator[EntryKey]: + return iter(self._entries.keys()) -- 2.39.5