|
24 | 24 | import time
|
25 | 25 | import typing
|
26 | 26 | import urllib.request
|
| 27 | +import uuid |
27 | 28 |
|
28 | 29 | from . import url_opener
|
29 | 30 | from .typelets import ExcType, ExcValue, ExcTraceback, Self
|
@@ -302,6 +303,83 @@ def _get_mon_config_key(interface: _RADOSInterface, key: str) -> io.BytesIO:
|
302 | 303 | raise OSError(ret, msg)
|
303 | 304 |
|
304 | 305 |
|
| 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 | + |
305 | 383 | def enable_rados_url_opener(
|
306 | 384 | cls: typing.Type[url_opener.URLOpener],
|
307 | 385 | *,
|
|
0 commit comments