Skip to content

Commit 3c42c69

Browse files
phlogistonjohnmergify[bot]
authored andcommitted
sambacc: add cluster meta rados classes
Add classes for the rados module to provide support for the ctdb module ClusterMeta protocols. The create_from_uri classmethod should be used to instantiate the new object as it hides the private _RADOSHandler type from other modules. Signed-off-by: John Mulligan <[email protected]>
1 parent c2964ae commit 3c42c69

File tree

1 file changed

+78
-0
lines changed

1 file changed

+78
-0
lines changed

sambacc/rados_opener.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import time
2525
import typing
2626
import urllib.request
27+
import uuid
2728

2829
from . import url_opener
2930
from .typelets import ExcType, ExcValue, ExcTraceback, Self
@@ -302,6 +303,83 @@ def _get_mon_config_key(interface: _RADOSInterface, key: str) -> io.BytesIO:
302303
raise OSError(ret, msg)
303304

304305

306+
class ClusterMetaRADOSHandle:
307+
"A Cluster Meta Object can load or dump persistent cluster descriptions."
308+
309+
def __init__(
310+
self,
311+
rados_obj: RADOSObjectRef,
312+
uri: str,
313+
*,
314+
read: bool,
315+
write: bool,
316+
locked: bool,
317+
):
318+
self._rados_obj = rados_obj
319+
self._uri = uri
320+
self._read = read
321+
self._write = write
322+
self._locked = locked
323+
if self._locked:
324+
self._lock_name = "cluster_meta"
325+
self._cookie = f"sambacc:{uuid.uuid4()}"
326+
327+
def load(self) -> typing.Any:
328+
if not self._read:
329+
raise ValueError("not readable")
330+
buf = self._rados_obj.read()
331+
if not buf:
332+
return {}
333+
return json.loads(buf)
334+
335+
def dump(self, data: typing.Any) -> None:
336+
if not self._read:
337+
raise ValueError("not writable")
338+
buf = json.dumps(data).encode("utf8")
339+
self._rados_obj.write_full(buf)
340+
341+
def __enter__(self) -> Self:
342+
if self._locked:
343+
self._rados_obj._acquire_lock_exclusive(
344+
self._lock_name, self._cookie
345+
)
346+
return self
347+
348+
def __exit__(
349+
self, exc_type: ExcType, exc_val: ExcValue, exc_tb: ExcTraceback
350+
) -> None:
351+
if self._locked:
352+
self._rados_obj._unlock(self._lock_name, self._cookie)
353+
return
354+
355+
356+
class ClusterMetaRADOSObject:
357+
def __init__(self, rados_handler: _RADOSHandler, uri: str) -> None:
358+
self._handler = rados_handler
359+
self._uri = uri
360+
361+
def open(
362+
self, *, read: bool = True, write: bool = False, locked: bool = False
363+
) -> ClusterMetaRADOSHandle:
364+
return ClusterMetaRADOSHandle(
365+
self._handler.get_object(self._uri),
366+
self._uri,
367+
read=read,
368+
write=write,
369+
locked=locked,
370+
)
371+
372+
@classmethod
373+
def create_from_uri(cls, uri: str) -> Self:
374+
"""Return a new ClusterMetaRADOSObject given a rados uri string.
375+
If rados module is unavailable RADOSUnsupported will be raised.
376+
"""
377+
handler = _RADOSHandler()
378+
if not handler._interface:
379+
raise RADOSUnsupported()
380+
return cls(handler, uri)
381+
382+
305383
def enable_rados_url_opener(
306384
cls: typing.Type[url_opener.URLOpener],
307385
*,

0 commit comments

Comments
 (0)